File Index
Files and directories
Sign in
FILE

ds4424.c

File preview with syntax highlighting.

linux-6.19.14/drivers/iio/dac/ds4424.c C
  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 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 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 DEFINE_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{
218	const struct i2c_device_id *id = i2c_client_get_device_id(client);
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		return -ENOMEM;
226
227	data = iio_priv(indio_dev);
228	i2c_set_clientdata(client, indio_dev);
229	data->client = client;
230	indio_dev->name = id->name;
231
232	data->vcc_reg = devm_regulator_get(&client->dev, "vcc");
233	if (IS_ERR(data->vcc_reg))
234		return dev_err_probe(&client->dev, PTR_ERR(data->vcc_reg),
235				     "Failed to get vcc-supply regulator.\n");
236
237	mutex_init(&data->lock);
238	ret = regulator_enable(data->vcc_reg);
239	if (ret < 0) {
240		dev_err(&client->dev,
241				"Unable to enable the regulator.\n");
242		return ret;
243	}
244
245	usleep_range(1000, 1200);
246	ret = ds4424_verify_chip(indio_dev);
247	if (ret < 0)
248		goto fail;
249
250	switch (id->driver_data) {
251	case ID_DS4422:
252		indio_dev->num_channels = DS4422_MAX_DAC_CHANNELS;
253		break;
254	case ID_DS4424:
255		indio_dev->num_channels = DS4424_MAX_DAC_CHANNELS;
256		break;
257	default:
258		dev_err(&client->dev,
259				"ds4424: Invalid chip id.\n");
260		ret = -ENXIO;
261		goto fail;
262	}
263
264	indio_dev->channels = ds4424_channels;
265	indio_dev->modes = INDIO_DIRECT_MODE;
266	indio_dev->info = &ds4424_info;
267
268	ret = iio_device_register(indio_dev);
269	if (ret < 0) {
270		dev_err(&client->dev,
271				"iio_device_register failed. ret: %d\n", ret);
272		goto fail;
273	}
274
275	return ret;
276
277fail:
278	regulator_disable(data->vcc_reg);
279	return ret;
280}
281
282static void ds4424_remove(struct i2c_client *client)
283{
284	struct iio_dev *indio_dev = i2c_get_clientdata(client);
285	struct ds4424_data *data = iio_priv(indio_dev);
286
287	iio_device_unregister(indio_dev);
288	regulator_disable(data->vcc_reg);
289}
290
291static const struct i2c_device_id ds4424_id[] = {
292	{ "ds4422", ID_DS4422 },
293	{ "ds4424", ID_DS4424 },
294	{ }
295};
296
297MODULE_DEVICE_TABLE(i2c, ds4424_id);
298
299static const struct of_device_id ds4424_of_match[] = {
300	{ .compatible = "maxim,ds4422" },
301	{ .compatible = "maxim,ds4424" },
302	{ }
303};
304
305MODULE_DEVICE_TABLE(of, ds4424_of_match);
306
307static struct i2c_driver ds4424_driver = {
308	.driver = {
309		.name	= "ds4424",
310		.of_match_table = ds4424_of_match,
311		.pm     = pm_sleep_ptr(&ds4424_pm_ops),
312	},
313	.probe		= ds4424_probe,
314	.remove		= ds4424_remove,
315	.id_table	= ds4424_id,
316};
317module_i2c_driver(ds4424_driver);
318
319MODULE_DESCRIPTION("Maxim DS4424 DAC Driver");
320MODULE_AUTHOR("Ismail H. Kose <ismail.kose@maximintegrated.com>");
321MODULE_AUTHOR("Vishal Sood <vishal.sood@maximintegrated.com>");
322MODULE_AUTHOR("David Jung <david.jung@maximintegrated.com>");
323MODULE_LICENSE("GPL v2");
~/ Read-only file preview.