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

m62332.c (5259B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *  m62332.c - Support for Mitsubishi m62332 DAC
      4 *
      5 *  Copyright (c) 2014 Dmitry Eremin-Solenikov
      6 *
      7 *  Based on max517 driver:
      8 *  Copyright (C) 2010, 2011 Roland Stigge <stigge@antcom.de>
      9 */
     10
     11#include <linux/module.h>
     12#include <linux/slab.h>
     13#include <linux/i2c.h>
     14#include <linux/err.h>
     15
     16#include <linux/iio/iio.h>
     17#include <linux/iio/driver.h>
     18
     19#include <linux/regulator/consumer.h>
     20
     21#define M62332_CHANNELS 2
     22
     23struct m62332_data {
     24	struct i2c_client	*client;
     25	struct regulator	*vcc;
     26	struct mutex		mutex;
     27	u8			raw[M62332_CHANNELS];
     28	u8			save[M62332_CHANNELS];
     29};
     30
     31static int m62332_set_value(struct iio_dev *indio_dev, u8 val, int channel)
     32{
     33	struct m62332_data *data = iio_priv(indio_dev);
     34	struct i2c_client *client = data->client;
     35	u8 outbuf[2];
     36	int res;
     37
     38	if (val == data->raw[channel])
     39		return 0;
     40
     41	outbuf[0] = channel;
     42	outbuf[1] = val;
     43
     44	mutex_lock(&data->mutex);
     45
     46	if (val) {
     47		res = regulator_enable(data->vcc);
     48		if (res)
     49			goto out;
     50	}
     51
     52	res = i2c_master_send(client, outbuf, ARRAY_SIZE(outbuf));
     53	if (res >= 0 && res != ARRAY_SIZE(outbuf))
     54		res = -EIO;
     55	if (res < 0)
     56		goto out;
     57
     58	data->raw[channel] = val;
     59
     60	if (!val)
     61		regulator_disable(data->vcc);
     62
     63	mutex_unlock(&data->mutex);
     64
     65	return 0;
     66
     67out:
     68	mutex_unlock(&data->mutex);
     69
     70	return res;
     71}
     72
     73static int m62332_read_raw(struct iio_dev *indio_dev,
     74			   struct iio_chan_spec const *chan,
     75			   int *val,
     76			   int *val2,
     77			   long mask)
     78{
     79	struct m62332_data *data = iio_priv(indio_dev);
     80	int ret;
     81
     82	switch (mask) {
     83	case IIO_CHAN_INFO_SCALE:
     84		/* Corresponds to Vref / 2^(bits) */
     85		ret = regulator_get_voltage(data->vcc);
     86		if (ret < 0)
     87			return ret;
     88
     89		*val = ret / 1000; /* mV */
     90		*val2 = 8;
     91
     92		return IIO_VAL_FRACTIONAL_LOG2;
     93	case IIO_CHAN_INFO_RAW:
     94		*val = data->raw[chan->channel];
     95
     96		return IIO_VAL_INT;
     97	case IIO_CHAN_INFO_OFFSET:
     98		*val = 1;
     99
    100		return IIO_VAL_INT;
    101	default:
    102		break;
    103	}
    104
    105	return -EINVAL;
    106}
    107
    108static int m62332_write_raw(struct iio_dev *indio_dev,
    109			    struct iio_chan_spec const *chan, int val, int val2,
    110			    long mask)
    111{
    112	switch (mask) {
    113	case IIO_CHAN_INFO_RAW:
    114		if (val < 0 || val > 255)
    115			return -EINVAL;
    116
    117		return m62332_set_value(indio_dev, val, chan->channel);
    118	default:
    119		break;
    120	}
    121
    122	return -EINVAL;
    123}
    124
    125static int m62332_suspend(struct device *dev)
    126{
    127	struct i2c_client *client = to_i2c_client(dev);
    128	struct iio_dev *indio_dev = i2c_get_clientdata(client);
    129	struct m62332_data *data = iio_priv(indio_dev);
    130	int ret;
    131
    132	data->save[0] = data->raw[0];
    133	data->save[1] = data->raw[1];
    134
    135	ret = m62332_set_value(indio_dev, 0, 0);
    136	if (ret < 0)
    137		return ret;
    138
    139	return m62332_set_value(indio_dev, 0, 1);
    140}
    141
    142static int m62332_resume(struct device *dev)
    143{
    144	struct i2c_client *client = to_i2c_client(dev);
    145	struct iio_dev *indio_dev = i2c_get_clientdata(client);
    146	struct m62332_data *data = iio_priv(indio_dev);
    147	int ret;
    148
    149	ret = m62332_set_value(indio_dev, data->save[0], 0);
    150	if (ret < 0)
    151		return ret;
    152
    153	return m62332_set_value(indio_dev, data->save[1], 1);
    154}
    155
    156static DEFINE_SIMPLE_DEV_PM_OPS(m62332_pm_ops, m62332_suspend, m62332_resume);
    157
    158static const struct iio_info m62332_info = {
    159	.read_raw = m62332_read_raw,
    160	.write_raw = m62332_write_raw,
    161};
    162
    163#define M62332_CHANNEL(chan) {					\
    164	.type = IIO_VOLTAGE,					\
    165	.indexed = 1,						\
    166	.output = 1,						\
    167	.channel = (chan),					\
    168	.datasheet_name = "CH" #chan,				\
    169	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
    170	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |	\
    171				    BIT(IIO_CHAN_INFO_OFFSET),	\
    172}
    173
    174static const struct iio_chan_spec m62332_channels[M62332_CHANNELS] = {
    175	M62332_CHANNEL(0),
    176	M62332_CHANNEL(1)
    177};
    178
    179static int m62332_probe(struct i2c_client *client,
    180			const struct i2c_device_id *id)
    181{
    182	struct m62332_data *data;
    183	struct iio_dev *indio_dev;
    184	int ret;
    185
    186	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
    187	if (!indio_dev)
    188		return -ENOMEM;
    189
    190	data = iio_priv(indio_dev);
    191	i2c_set_clientdata(client, indio_dev);
    192	data->client = client;
    193
    194	mutex_init(&data->mutex);
    195
    196	data->vcc = devm_regulator_get(&client->dev, "VCC");
    197	if (IS_ERR(data->vcc))
    198		return PTR_ERR(data->vcc);
    199
    200	indio_dev->num_channels = ARRAY_SIZE(m62332_channels);
    201	indio_dev->channels = m62332_channels;
    202	indio_dev->modes = INDIO_DIRECT_MODE;
    203	indio_dev->info = &m62332_info;
    204
    205	ret = iio_map_array_register(indio_dev, client->dev.platform_data);
    206	if (ret < 0)
    207		return ret;
    208
    209	ret = iio_device_register(indio_dev);
    210	if (ret < 0)
    211		goto err;
    212
    213	return 0;
    214
    215err:
    216	iio_map_array_unregister(indio_dev);
    217
    218	return ret;
    219}
    220
    221static int m62332_remove(struct i2c_client *client)
    222{
    223	struct iio_dev *indio_dev = i2c_get_clientdata(client);
    224
    225	iio_device_unregister(indio_dev);
    226	iio_map_array_unregister(indio_dev);
    227	m62332_set_value(indio_dev, 0, 0);
    228	m62332_set_value(indio_dev, 0, 1);
    229
    230	return 0;
    231}
    232
    233static const struct i2c_device_id m62332_id[] = {
    234	{ "m62332", },
    235	{ }
    236};
    237MODULE_DEVICE_TABLE(i2c, m62332_id);
    238
    239static struct i2c_driver m62332_driver = {
    240	.driver = {
    241		.name	= "m62332",
    242		.pm	= pm_sleep_ptr(&m62332_pm_ops),
    243	},
    244	.probe		= m62332_probe,
    245	.remove		= m62332_remove,
    246	.id_table	= m62332_id,
    247};
    248module_i2c_driver(m62332_driver);
    249
    250MODULE_AUTHOR("Dmitry Eremin-Solenikov");
    251MODULE_DESCRIPTION("M62332 8-bit DAC");
    252MODULE_LICENSE("GPL v2");