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

ds4424.c (7176B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Maxim Integrated
      4 * 7-bit, Multi-Channel Sink/Source Current DAC Driver
      5 * Copyright (C) 2017 Maxim Integrated
      6 */
      7
      8#include <linux/kernel.h>
      9#include <linux/module.h>
     10#include <linux/i2c.h>
     11#include <linux/regulator/consumer.h>
     12#include <linux/err.h>
     13#include <linux/delay.h>
     14#include <linux/iio/iio.h>
     15#include <linux/iio/driver.h>
     16#include <linux/iio/machine.h>
     17#include <linux/iio/consumer.h>
     18
     19#define DS4422_MAX_DAC_CHANNELS		2
     20#define DS4424_MAX_DAC_CHANNELS		4
     21
     22#define DS4424_DAC_ADDR(chan)   ((chan) + 0xf8)
     23#define DS4424_SOURCE_I		1
     24#define DS4424_SINK_I		0
     25
     26#define DS4424_CHANNEL(chan) { \
     27	.type = IIO_CURRENT, \
     28	.indexed = 1, \
     29	.output = 1, \
     30	.channel = chan, \
     31	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
     32}
     33
     34/*
     35 * DS4424 DAC control register 8 bits
     36 * [7]		0: to sink; 1: to source
     37 * [6:0]	steps to sink/source
     38 * bit[7] looks like a sign bit, but the value of the register is
     39 * not a two's complement code considering the bit[6:0] is a absolute
     40 * distance from the zero point.
     41 */
     42union ds4424_raw_data {
     43	struct {
     44		u8 dx:7;
     45		u8 source_bit:1;
     46	};
     47	u8 bits;
     48};
     49
     50enum ds4424_device_ids {
     51	ID_DS4422,
     52	ID_DS4424,
     53};
     54
     55struct ds4424_data {
     56	struct i2c_client *client;
     57	struct mutex lock;
     58	uint8_t save[DS4424_MAX_DAC_CHANNELS];
     59	struct regulator *vcc_reg;
     60	uint8_t raw[DS4424_MAX_DAC_CHANNELS];
     61};
     62
     63static const struct iio_chan_spec ds4424_channels[] = {
     64	DS4424_CHANNEL(0),
     65	DS4424_CHANNEL(1),
     66	DS4424_CHANNEL(2),
     67	DS4424_CHANNEL(3),
     68};
     69
     70static int ds4424_get_value(struct iio_dev *indio_dev,
     71			     int *val, int channel)
     72{
     73	struct ds4424_data *data = iio_priv(indio_dev);
     74	int ret;
     75
     76	mutex_lock(&data->lock);
     77	ret = i2c_smbus_read_byte_data(data->client, DS4424_DAC_ADDR(channel));
     78	if (ret < 0)
     79		goto fail;
     80
     81	*val = ret;
     82
     83fail:
     84	mutex_unlock(&data->lock);
     85	return ret;
     86}
     87
     88static int ds4424_set_value(struct iio_dev *indio_dev,
     89			     int val, struct iio_chan_spec const *chan)
     90{
     91	struct ds4424_data *data = iio_priv(indio_dev);
     92	int ret;
     93
     94	mutex_lock(&data->lock);
     95	ret = i2c_smbus_write_byte_data(data->client,
     96			DS4424_DAC_ADDR(chan->channel), val);
     97	if (ret < 0)
     98		goto fail;
     99
    100	data->raw[chan->channel] = val;
    101
    102fail:
    103	mutex_unlock(&data->lock);
    104	return ret;
    105}
    106
    107static int ds4424_read_raw(struct iio_dev *indio_dev,
    108			   struct iio_chan_spec const *chan,
    109			   int *val, int *val2, long mask)
    110{
    111	union ds4424_raw_data raw;
    112	int ret;
    113
    114	switch (mask) {
    115	case IIO_CHAN_INFO_RAW:
    116		ret = ds4424_get_value(indio_dev, val, chan->channel);
    117		if (ret < 0) {
    118			pr_err("%s : ds4424_get_value returned %d\n",
    119							__func__, ret);
    120			return ret;
    121		}
    122		raw.bits = *val;
    123		*val = raw.dx;
    124		if (raw.source_bit == DS4424_SINK_I)
    125			*val = -*val;
    126		return IIO_VAL_INT;
    127
    128	default:
    129		return -EINVAL;
    130	}
    131}
    132
    133static int ds4424_write_raw(struct iio_dev *indio_dev,
    134			     struct iio_chan_spec const *chan,
    135			     int val, int val2, long mask)
    136{
    137	union ds4424_raw_data raw;
    138
    139	if (val2 != 0)
    140		return -EINVAL;
    141
    142	switch (mask) {
    143	case IIO_CHAN_INFO_RAW:
    144		if (val < S8_MIN || val > S8_MAX)
    145			return -EINVAL;
    146
    147		if (val > 0) {
    148			raw.source_bit = DS4424_SOURCE_I;
    149			raw.dx = val;
    150		} else {
    151			raw.source_bit = DS4424_SINK_I;
    152			raw.dx = -val;
    153		}
    154
    155		return ds4424_set_value(indio_dev, raw.bits, chan);
    156
    157	default:
    158		return -EINVAL;
    159	}
    160}
    161
    162static int ds4424_verify_chip(struct iio_dev *indio_dev)
    163{
    164	int ret, val;
    165
    166	ret = ds4424_get_value(indio_dev, &val, 0);
    167	if (ret < 0)
    168		dev_err(&indio_dev->dev,
    169				"%s failed. ret: %d\n", __func__, ret);
    170
    171	return ret;
    172}
    173
    174static int __maybe_unused ds4424_suspend(struct device *dev)
    175{
    176	struct i2c_client *client = to_i2c_client(dev);
    177	struct iio_dev *indio_dev = i2c_get_clientdata(client);
    178	struct ds4424_data *data = iio_priv(indio_dev);
    179	int ret = 0;
    180	int i;
    181
    182	for (i = 0; i < indio_dev->num_channels; i++) {
    183		data->save[i] = data->raw[i];
    184		ret = ds4424_set_value(indio_dev, 0,
    185				&indio_dev->channels[i]);
    186		if (ret < 0)
    187			return ret;
    188	}
    189	return ret;
    190}
    191
    192static int __maybe_unused ds4424_resume(struct device *dev)
    193{
    194	struct i2c_client *client = to_i2c_client(dev);
    195	struct iio_dev *indio_dev = i2c_get_clientdata(client);
    196	struct ds4424_data *data = iio_priv(indio_dev);
    197	int ret = 0;
    198	int i;
    199
    200	for (i = 0; i < indio_dev->num_channels; i++) {
    201		ret = ds4424_set_value(indio_dev, data->save[i],
    202				&indio_dev->channels[i]);
    203		if (ret < 0)
    204			return ret;
    205	}
    206	return ret;
    207}
    208
    209static SIMPLE_DEV_PM_OPS(ds4424_pm_ops, ds4424_suspend, ds4424_resume);
    210
    211static const struct iio_info ds4424_info = {
    212	.read_raw = ds4424_read_raw,
    213	.write_raw = ds4424_write_raw,
    214};
    215
    216static int ds4424_probe(struct i2c_client *client,
    217			const struct i2c_device_id *id)
    218{
    219	struct ds4424_data *data;
    220	struct iio_dev *indio_dev;
    221	int ret;
    222
    223	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
    224	if (!indio_dev) {
    225		dev_err(&client->dev, "iio dev alloc failed.\n");
    226		return -ENOMEM;
    227	}
    228
    229	data = iio_priv(indio_dev);
    230	i2c_set_clientdata(client, indio_dev);
    231	data->client = client;
    232	indio_dev->name = id->name;
    233
    234	data->vcc_reg = devm_regulator_get(&client->dev, "vcc");
    235	if (IS_ERR(data->vcc_reg))
    236		return dev_err_probe(&client->dev, PTR_ERR(data->vcc_reg),
    237				     "Failed to get vcc-supply regulator.\n");
    238
    239	mutex_init(&data->lock);
    240	ret = regulator_enable(data->vcc_reg);
    241	if (ret < 0) {
    242		dev_err(&client->dev,
    243				"Unable to enable the regulator.\n");
    244		return ret;
    245	}
    246
    247	usleep_range(1000, 1200);
    248	ret = ds4424_verify_chip(indio_dev);
    249	if (ret < 0)
    250		goto fail;
    251
    252	switch (id->driver_data) {
    253	case ID_DS4422:
    254		indio_dev->num_channels = DS4422_MAX_DAC_CHANNELS;
    255		break;
    256	case ID_DS4424:
    257		indio_dev->num_channels = DS4424_MAX_DAC_CHANNELS;
    258		break;
    259	default:
    260		dev_err(&client->dev,
    261				"ds4424: Invalid chip id.\n");
    262		ret = -ENXIO;
    263		goto fail;
    264	}
    265
    266	indio_dev->channels = ds4424_channels;
    267	indio_dev->modes = INDIO_DIRECT_MODE;
    268	indio_dev->info = &ds4424_info;
    269
    270	ret = iio_device_register(indio_dev);
    271	if (ret < 0) {
    272		dev_err(&client->dev,
    273				"iio_device_register failed. ret: %d\n", ret);
    274		goto fail;
    275	}
    276
    277	return ret;
    278
    279fail:
    280	regulator_disable(data->vcc_reg);
    281	return ret;
    282}
    283
    284static int ds4424_remove(struct i2c_client *client)
    285{
    286	struct iio_dev *indio_dev = i2c_get_clientdata(client);
    287	struct ds4424_data *data = iio_priv(indio_dev);
    288
    289	iio_device_unregister(indio_dev);
    290	regulator_disable(data->vcc_reg);
    291
    292	return 0;
    293}
    294
    295static const struct i2c_device_id ds4424_id[] = {
    296	{ "ds4422", ID_DS4422 },
    297	{ "ds4424", ID_DS4424 },
    298	{ }
    299};
    300
    301MODULE_DEVICE_TABLE(i2c, ds4424_id);
    302
    303static const struct of_device_id ds4424_of_match[] = {
    304	{ .compatible = "maxim,ds4422" },
    305	{ .compatible = "maxim,ds4424" },
    306	{ },
    307};
    308
    309MODULE_DEVICE_TABLE(of, ds4424_of_match);
    310
    311static struct i2c_driver ds4424_driver = {
    312	.driver = {
    313		.name	= "ds4424",
    314		.of_match_table = ds4424_of_match,
    315		.pm     = &ds4424_pm_ops,
    316	},
    317	.probe		= ds4424_probe,
    318	.remove		= ds4424_remove,
    319	.id_table	= ds4424_id,
    320};
    321module_i2c_driver(ds4424_driver);
    322
    323MODULE_DESCRIPTION("Maxim DS4424 DAC Driver");
    324MODULE_AUTHOR("Ismail H. Kose <ismail.kose@maximintegrated.com>");
    325MODULE_AUTHOR("Vishal Sood <vishal.sood@maximintegrated.com>");
    326MODULE_AUTHOR("David Jung <david.jung@maximintegrated.com>");
    327MODULE_LICENSE("GPL v2");