xref: /openbmc/linux/drivers/iio/dac/ds4424.c (revision 5c306de8)
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  */
42 union ds4424_raw_data {
43 	struct {
44 		u8 dx:7;
45 		u8 source_bit:1;
46 	};
47 	u8 bits;
48 };
49 
50 enum ds4424_device_ids {
51 	ID_DS4422,
52 	ID_DS4424,
53 };
54 
55 struct 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 
63 static 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 
70 static 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 
83 fail:
84 	mutex_unlock(&data->lock);
85 	return ret;
86 }
87 
88 static 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 
102 fail:
103 	mutex_unlock(&data->lock);
104 	return ret;
105 }
106 
107 static 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 
133 static 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 
162 static 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 
174 static 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 
192 static 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 
209 static DEFINE_SIMPLE_DEV_PM_OPS(ds4424_pm_ops, ds4424_suspend, ds4424_resume);
210 
211 static const struct iio_info ds4424_info = {
212 	.read_raw = ds4424_read_raw,
213 	.write_raw = ds4424_write_raw,
214 };
215 
216 static 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 
279 fail:
280 	regulator_disable(data->vcc_reg);
281 	return ret;
282 }
283 
284 static void 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 
293 static const struct i2c_device_id ds4424_id[] = {
294 	{ "ds4422", ID_DS4422 },
295 	{ "ds4424", ID_DS4424 },
296 	{ }
297 };
298 
299 MODULE_DEVICE_TABLE(i2c, ds4424_id);
300 
301 static const struct of_device_id ds4424_of_match[] = {
302 	{ .compatible = "maxim,ds4422" },
303 	{ .compatible = "maxim,ds4424" },
304 	{ },
305 };
306 
307 MODULE_DEVICE_TABLE(of, ds4424_of_match);
308 
309 static struct i2c_driver ds4424_driver = {
310 	.driver = {
311 		.name	= "ds4424",
312 		.of_match_table = ds4424_of_match,
313 		.pm     = pm_sleep_ptr(&ds4424_pm_ops),
314 	},
315 	.probe		= ds4424_probe,
316 	.remove		= ds4424_remove,
317 	.id_table	= ds4424_id,
318 };
319 module_i2c_driver(ds4424_driver);
320 
321 MODULE_DESCRIPTION("Maxim DS4424 DAC Driver");
322 MODULE_AUTHOR("Ismail H. Kose <ismail.kose@maximintegrated.com>");
323 MODULE_AUTHOR("Vishal Sood <vishal.sood@maximintegrated.com>");
324 MODULE_AUTHOR("David Jung <david.jung@maximintegrated.com>");
325 MODULE_LICENSE("GPL v2");
326