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-dac082s085.c (9051B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * ti-dac082s085.c - Texas Instruments 8/10/12-bit 2/4-channel DAC driver
      4 *
      5 * Copyright (C) 2017 KUNBUS GmbH
      6 *
      7 * https://www.ti.com/lit/ds/symlink/dac082s085.pdf
      8 * https://www.ti.com/lit/ds/symlink/dac102s085.pdf
      9 * https://www.ti.com/lit/ds/symlink/dac122s085.pdf
     10 * https://www.ti.com/lit/ds/symlink/dac084s085.pdf
     11 * https://www.ti.com/lit/ds/symlink/dac104s085.pdf
     12 * https://www.ti.com/lit/ds/symlink/dac124s085.pdf
     13 */
     14
     15#include <linux/iio/iio.h>
     16#include <linux/module.h>
     17#include <linux/mod_devicetable.h>
     18#include <linux/regulator/consumer.h>
     19#include <linux/spi/spi.h>
     20
     21enum { dual_8bit, dual_10bit, dual_12bit, quad_8bit, quad_10bit, quad_12bit };
     22
     23struct ti_dac_spec {
     24	u8 num_channels;
     25	u8 resolution;
     26};
     27
     28static const struct ti_dac_spec ti_dac_spec[] = {
     29	[dual_8bit]  = { .num_channels = 2, .resolution = 8  },
     30	[dual_10bit] = { .num_channels = 2, .resolution = 10 },
     31	[dual_12bit] = { .num_channels = 2, .resolution = 12 },
     32	[quad_8bit]  = { .num_channels = 4, .resolution = 8  },
     33	[quad_10bit] = { .num_channels = 4, .resolution = 10 },
     34	[quad_12bit] = { .num_channels = 4, .resolution = 12 },
     35};
     36
     37/**
     38 * struct ti_dac_chip - TI DAC chip
     39 * @lock: protects write sequences
     40 * @vref: regulator generating Vref
     41 * @mesg: SPI message to perform a write
     42 * @xfer: SPI transfer used by @mesg
     43 * @val: cached value of each output
     44 * @powerdown: whether the chip is powered down
     45 * @powerdown_mode: selected by the user
     46 * @resolution: resolution of the chip
     47 * @buf: buffer for @xfer
     48 */
     49struct ti_dac_chip {
     50	struct mutex lock;
     51	struct regulator *vref;
     52	struct spi_message mesg;
     53	struct spi_transfer xfer;
     54	u16 val[4];
     55	bool powerdown;
     56	u8 powerdown_mode;
     57	u8 resolution;
     58	u8 buf[2] ____cacheline_aligned;
     59};
     60
     61#define WRITE_NOT_UPDATE(chan)	(0x00 | (chan) << 6)
     62#define WRITE_AND_UPDATE(chan)	(0x10 | (chan) << 6)
     63#define WRITE_ALL_UPDATE	 0x20
     64#define POWERDOWN(mode) 	(0x30 | ((mode) + 1) << 6)
     65
     66static int ti_dac_cmd(struct ti_dac_chip *ti_dac, u8 cmd, u16 val)
     67{
     68	u8 shift = 12 - ti_dac->resolution;
     69
     70	ti_dac->buf[0] = cmd | (val >> (8 - shift));
     71	ti_dac->buf[1] = (val << shift) & 0xff;
     72	return spi_sync(ti_dac->mesg.spi, &ti_dac->mesg);
     73}
     74
     75static const char * const ti_dac_powerdown_modes[] = {
     76	"2.5kohm_to_gnd", "100kohm_to_gnd", "three_state",
     77};
     78
     79static int ti_dac_get_powerdown_mode(struct iio_dev *indio_dev,
     80				     const struct iio_chan_spec *chan)
     81{
     82	struct ti_dac_chip *ti_dac = iio_priv(indio_dev);
     83
     84	return ti_dac->powerdown_mode;
     85}
     86
     87static int ti_dac_set_powerdown_mode(struct iio_dev *indio_dev,
     88				     const struct iio_chan_spec *chan,
     89				     unsigned int mode)
     90{
     91	struct ti_dac_chip *ti_dac = iio_priv(indio_dev);
     92	int ret = 0;
     93
     94	if (ti_dac->powerdown_mode == mode)
     95		return 0;
     96
     97	mutex_lock(&ti_dac->lock);
     98	if (ti_dac->powerdown) {
     99		ret = ti_dac_cmd(ti_dac, POWERDOWN(mode), 0);
    100		if (ret)
    101			goto out;
    102	}
    103	ti_dac->powerdown_mode = mode;
    104
    105out:
    106	mutex_unlock(&ti_dac->lock);
    107	return ret;
    108}
    109
    110static const struct iio_enum ti_dac_powerdown_mode = {
    111	.items = ti_dac_powerdown_modes,
    112	.num_items = ARRAY_SIZE(ti_dac_powerdown_modes),
    113	.get = ti_dac_get_powerdown_mode,
    114	.set = ti_dac_set_powerdown_mode,
    115};
    116
    117static ssize_t ti_dac_read_powerdown(struct iio_dev *indio_dev,
    118				     uintptr_t private,
    119				     const struct iio_chan_spec *chan,
    120				     char *buf)
    121{
    122	struct ti_dac_chip *ti_dac = iio_priv(indio_dev);
    123
    124	return sysfs_emit(buf, "%d\n", ti_dac->powerdown);
    125}
    126
    127static ssize_t ti_dac_write_powerdown(struct iio_dev *indio_dev,
    128				      uintptr_t private,
    129				      const struct iio_chan_spec *chan,
    130				      const char *buf, size_t len)
    131{
    132	struct ti_dac_chip *ti_dac = iio_priv(indio_dev);
    133	bool powerdown;
    134	int ret;
    135
    136	ret = kstrtobool(buf, &powerdown);
    137	if (ret)
    138		return ret;
    139
    140	if (ti_dac->powerdown == powerdown)
    141		return len;
    142
    143	mutex_lock(&ti_dac->lock);
    144	if (powerdown)
    145		ret = ti_dac_cmd(ti_dac, POWERDOWN(ti_dac->powerdown_mode), 0);
    146	else
    147		ret = ti_dac_cmd(ti_dac, WRITE_AND_UPDATE(0), ti_dac->val[0]);
    148	if (!ret)
    149		ti_dac->powerdown = powerdown;
    150	mutex_unlock(&ti_dac->lock);
    151
    152	return ret ? ret : len;
    153}
    154
    155static const struct iio_chan_spec_ext_info ti_dac_ext_info[] = {
    156	{
    157		.name	   = "powerdown",
    158		.read	   = ti_dac_read_powerdown,
    159		.write	   = ti_dac_write_powerdown,
    160		.shared	   = IIO_SHARED_BY_TYPE,
    161	},
    162	IIO_ENUM("powerdown_mode", IIO_SHARED_BY_TYPE, &ti_dac_powerdown_mode),
    163	IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE, &ti_dac_powerdown_mode),
    164	{ },
    165};
    166
    167#define TI_DAC_CHANNEL(chan) {					\
    168	.type = IIO_VOLTAGE,					\
    169	.channel = (chan),					\
    170	.address = (chan),					\
    171	.indexed = true,					\
    172	.output = true,						\
    173	.datasheet_name = (const char[]){ 'A' + (chan), 0 },	\
    174	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
    175	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),	\
    176	.ext_info = ti_dac_ext_info,				\
    177}
    178
    179static const struct iio_chan_spec ti_dac_channels[] = {
    180	TI_DAC_CHANNEL(0),
    181	TI_DAC_CHANNEL(1),
    182	TI_DAC_CHANNEL(2),
    183	TI_DAC_CHANNEL(3),
    184};
    185
    186static int ti_dac_read_raw(struct iio_dev *indio_dev,
    187			   struct iio_chan_spec const *chan,
    188			   int *val, int *val2, long mask)
    189{
    190	struct ti_dac_chip *ti_dac = iio_priv(indio_dev);
    191	int ret;
    192
    193	switch (mask) {
    194	case IIO_CHAN_INFO_RAW:
    195		*val = ti_dac->val[chan->channel];
    196		ret = IIO_VAL_INT;
    197		break;
    198
    199	case IIO_CHAN_INFO_SCALE:
    200		ret = regulator_get_voltage(ti_dac->vref);
    201		if (ret < 0)
    202			return ret;
    203
    204		*val = ret / 1000;
    205		*val2 = ti_dac->resolution;
    206		ret = IIO_VAL_FRACTIONAL_LOG2;
    207		break;
    208
    209	default:
    210		ret = -EINVAL;
    211	}
    212
    213	return ret;
    214}
    215
    216static int ti_dac_write_raw(struct iio_dev *indio_dev,
    217			    struct iio_chan_spec const *chan,
    218			    int val, int val2, long mask)
    219{
    220	struct ti_dac_chip *ti_dac = iio_priv(indio_dev);
    221	int ret;
    222
    223	switch (mask) {
    224	case IIO_CHAN_INFO_RAW:
    225		if (ti_dac->val[chan->channel] == val)
    226			return 0;
    227
    228		if (val >= (1 << ti_dac->resolution) || val < 0)
    229			return -EINVAL;
    230
    231		if (ti_dac->powerdown)
    232			return -EBUSY;
    233
    234		mutex_lock(&ti_dac->lock);
    235		ret = ti_dac_cmd(ti_dac, WRITE_AND_UPDATE(chan->channel), val);
    236		if (!ret)
    237			ti_dac->val[chan->channel] = val;
    238		mutex_unlock(&ti_dac->lock);
    239		break;
    240
    241	default:
    242		ret = -EINVAL;
    243	}
    244
    245	return ret;
    246}
    247
    248static int ti_dac_write_raw_get_fmt(struct iio_dev *indio_dev,
    249				    struct iio_chan_spec const *chan, long mask)
    250{
    251	return IIO_VAL_INT;
    252}
    253
    254static const struct iio_info ti_dac_info = {
    255	.read_raw	   = ti_dac_read_raw,
    256	.write_raw	   = ti_dac_write_raw,
    257	.write_raw_get_fmt = ti_dac_write_raw_get_fmt,
    258};
    259
    260static int ti_dac_probe(struct spi_device *spi)
    261{
    262	struct device *dev = &spi->dev;
    263	const struct ti_dac_spec *spec;
    264	struct ti_dac_chip *ti_dac;
    265	struct iio_dev *indio_dev;
    266	int ret;
    267
    268	indio_dev = devm_iio_device_alloc(dev, sizeof(*ti_dac));
    269	if (!indio_dev)
    270		return -ENOMEM;
    271
    272	indio_dev->info = &ti_dac_info;
    273	indio_dev->name = spi->modalias;
    274	indio_dev->modes = INDIO_DIRECT_MODE;
    275	indio_dev->channels = ti_dac_channels;
    276	spi_set_drvdata(spi, indio_dev);
    277
    278	ti_dac = iio_priv(indio_dev);
    279	ti_dac->xfer.tx_buf = &ti_dac->buf;
    280	ti_dac->xfer.len = sizeof(ti_dac->buf);
    281	spi_message_init_with_transfers(&ti_dac->mesg, &ti_dac->xfer, 1);
    282	ti_dac->mesg.spi = spi;
    283
    284	spec = &ti_dac_spec[spi_get_device_id(spi)->driver_data];
    285	indio_dev->num_channels = spec->num_channels;
    286	ti_dac->resolution = spec->resolution;
    287
    288	ti_dac->vref = devm_regulator_get(dev, "vref");
    289	if (IS_ERR(ti_dac->vref))
    290		return PTR_ERR(ti_dac->vref);
    291
    292	ret = regulator_enable(ti_dac->vref);
    293	if (ret < 0)
    294		return ret;
    295
    296	mutex_init(&ti_dac->lock);
    297
    298	ret = ti_dac_cmd(ti_dac, WRITE_ALL_UPDATE, 0);
    299	if (ret) {
    300		dev_err(dev, "failed to initialize outputs to 0\n");
    301		goto err;
    302	}
    303
    304	ret = iio_device_register(indio_dev);
    305	if (ret)
    306		goto err;
    307
    308	return 0;
    309
    310err:
    311	mutex_destroy(&ti_dac->lock);
    312	regulator_disable(ti_dac->vref);
    313	return ret;
    314}
    315
    316static void ti_dac_remove(struct spi_device *spi)
    317{
    318	struct iio_dev *indio_dev = spi_get_drvdata(spi);
    319	struct ti_dac_chip *ti_dac = iio_priv(indio_dev);
    320
    321	iio_device_unregister(indio_dev);
    322	mutex_destroy(&ti_dac->lock);
    323	regulator_disable(ti_dac->vref);
    324}
    325
    326static const struct of_device_id ti_dac_of_id[] = {
    327	{ .compatible = "ti,dac082s085" },
    328	{ .compatible = "ti,dac102s085" },
    329	{ .compatible = "ti,dac122s085" },
    330	{ .compatible = "ti,dac084s085" },
    331	{ .compatible = "ti,dac104s085" },
    332	{ .compatible = "ti,dac124s085" },
    333	{ }
    334};
    335MODULE_DEVICE_TABLE(of, ti_dac_of_id);
    336
    337static const struct spi_device_id ti_dac_spi_id[] = {
    338	{ "dac082s085", dual_8bit  },
    339	{ "dac102s085", dual_10bit },
    340	{ "dac122s085", dual_12bit },
    341	{ "dac084s085", quad_8bit  },
    342	{ "dac104s085", quad_10bit },
    343	{ "dac124s085", quad_12bit },
    344	{ }
    345};
    346MODULE_DEVICE_TABLE(spi, ti_dac_spi_id);
    347
    348static struct spi_driver ti_dac_driver = {
    349	.driver = {
    350		.name		= "ti-dac082s085",
    351		.of_match_table	= ti_dac_of_id,
    352	},
    353	.probe	  = ti_dac_probe,
    354	.remove   = ti_dac_remove,
    355	.id_table = ti_dac_spi_id,
    356};
    357module_spi_driver(ti_dac_driver);
    358
    359MODULE_AUTHOR("Lukas Wunner <lukas@wunner.de>");
    360MODULE_DESCRIPTION("Texas Instruments 8/10/12-bit 2/4-channel DAC driver");
    361MODULE_LICENSE("GPL v2");