1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * ti-dac5571.c - Texas Instruments 8/10/12-bit 1/4-channel DAC driver |
4 | * |
5 | * Copyright (C) 2018 Prevas A/S |
6 | * |
7 | * https://www.ti.com/lit/ds/symlink/dac5571.pdf |
8 | * https://www.ti.com/lit/ds/symlink/dac6571.pdf |
9 | * https://www.ti.com/lit/ds/symlink/dac7571.pdf |
10 | * https://www.ti.com/lit/ds/symlink/dac5574.pdf |
11 | * https://www.ti.com/lit/ds/symlink/dac6574.pdf |
12 | * https://www.ti.com/lit/ds/symlink/dac7574.pdf |
13 | * https://www.ti.com/lit/ds/symlink/dac5573.pdf |
14 | * https://www.ti.com/lit/ds/symlink/dac6573.pdf |
15 | * https://www.ti.com/lit/ds/symlink/dac7573.pdf |
16 | * https://www.ti.com/lit/ds/symlink/dac121c081.pdf |
17 | */ |
18 | |
19 | #include <linux/iio/iio.h> |
20 | #include <linux/i2c.h> |
21 | #include <linux/module.h> |
22 | #include <linux/mod_devicetable.h> |
23 | #include <linux/property.h> |
24 | #include <linux/regulator/consumer.h> |
25 | |
26 | enum chip_id { |
27 | single_8bit, single_10bit, single_12bit, |
28 | quad_8bit, quad_10bit, quad_12bit |
29 | }; |
30 | |
31 | struct dac5571_spec { |
32 | u8 num_channels; |
33 | u8 resolution; |
34 | }; |
35 | |
36 | static const struct dac5571_spec dac5571_spec[] = { |
37 | [single_8bit] = {.num_channels = 1, .resolution = 8}, |
38 | [single_10bit] = {.num_channels = 1, .resolution = 10}, |
39 | [single_12bit] = {.num_channels = 1, .resolution = 12}, |
40 | [quad_8bit] = {.num_channels = 4, .resolution = 8}, |
41 | [quad_10bit] = {.num_channels = 4, .resolution = 10}, |
42 | [quad_12bit] = {.num_channels = 4, .resolution = 12}, |
43 | }; |
44 | |
45 | struct dac5571_data { |
46 | struct i2c_client *client; |
47 | int id; |
48 | struct mutex lock; |
49 | struct regulator *vref; |
50 | u16 val[4]; |
51 | bool powerdown[4]; |
52 | u8 powerdown_mode[4]; |
53 | struct dac5571_spec const *spec; |
54 | int (*dac5571_cmd)(struct dac5571_data *data, int channel, u16 val); |
55 | int (*dac5571_pwrdwn)(struct dac5571_data *data, int channel, u8 pwrdwn); |
56 | u8 buf[3] __aligned(IIO_DMA_MINALIGN); |
57 | }; |
58 | |
59 | #define DAC5571_POWERDOWN(mode) ((mode) + 1) |
60 | #define DAC5571_POWERDOWN_FLAG BIT(0) |
61 | #define DAC5571_CHANNEL_SELECT 1 |
62 | #define DAC5571_LOADMODE_DIRECT BIT(4) |
63 | #define DAC5571_SINGLE_PWRDWN_BITS 4 |
64 | #define DAC5571_QUAD_PWRDWN_BITS 6 |
65 | |
66 | static int dac5571_cmd_single(struct dac5571_data *data, int channel, u16 val) |
67 | { |
68 | unsigned int shift; |
69 | |
70 | shift = 12 - data->spec->resolution; |
71 | data->buf[1] = val << shift; |
72 | data->buf[0] = val >> (8 - shift); |
73 | |
74 | if (i2c_master_send(client: data->client, buf: data->buf, count: 2) != 2) |
75 | return -EIO; |
76 | |
77 | return 0; |
78 | } |
79 | |
80 | static int dac5571_cmd_quad(struct dac5571_data *data, int channel, u16 val) |
81 | { |
82 | unsigned int shift; |
83 | |
84 | shift = 16 - data->spec->resolution; |
85 | data->buf[2] = val << shift; |
86 | data->buf[1] = (val >> (8 - shift)); |
87 | data->buf[0] = (channel << DAC5571_CHANNEL_SELECT) | |
88 | DAC5571_LOADMODE_DIRECT; |
89 | |
90 | if (i2c_master_send(client: data->client, buf: data->buf, count: 3) != 3) |
91 | return -EIO; |
92 | |
93 | return 0; |
94 | } |
95 | |
96 | static int dac5571_pwrdwn_single(struct dac5571_data *data, int channel, u8 pwrdwn) |
97 | { |
98 | data->buf[1] = 0; |
99 | data->buf[0] = pwrdwn << DAC5571_SINGLE_PWRDWN_BITS; |
100 | |
101 | if (i2c_master_send(client: data->client, buf: data->buf, count: 2) != 2) |
102 | return -EIO; |
103 | |
104 | return 0; |
105 | } |
106 | |
107 | static int dac5571_pwrdwn_quad(struct dac5571_data *data, int channel, u8 pwrdwn) |
108 | { |
109 | data->buf[2] = 0; |
110 | data->buf[1] = pwrdwn << DAC5571_QUAD_PWRDWN_BITS; |
111 | data->buf[0] = (channel << DAC5571_CHANNEL_SELECT) | |
112 | DAC5571_LOADMODE_DIRECT | DAC5571_POWERDOWN_FLAG; |
113 | |
114 | if (i2c_master_send(client: data->client, buf: data->buf, count: 3) != 3) |
115 | return -EIO; |
116 | |
117 | return 0; |
118 | } |
119 | |
120 | static const char *const dac5571_powerdown_modes[] = { |
121 | "1kohm_to_gnd" , "100kohm_to_gnd" , "three_state" , |
122 | }; |
123 | |
124 | static int dac5571_get_powerdown_mode(struct iio_dev *indio_dev, |
125 | const struct iio_chan_spec *chan) |
126 | { |
127 | struct dac5571_data *data = iio_priv(indio_dev); |
128 | |
129 | return data->powerdown_mode[chan->channel]; |
130 | } |
131 | |
132 | static int dac5571_set_powerdown_mode(struct iio_dev *indio_dev, |
133 | const struct iio_chan_spec *chan, |
134 | unsigned int mode) |
135 | { |
136 | struct dac5571_data *data = iio_priv(indio_dev); |
137 | int ret = 0; |
138 | |
139 | if (data->powerdown_mode[chan->channel] == mode) |
140 | return 0; |
141 | |
142 | mutex_lock(&data->lock); |
143 | if (data->powerdown[chan->channel]) { |
144 | ret = data->dac5571_pwrdwn(data, chan->channel, |
145 | DAC5571_POWERDOWN(mode)); |
146 | if (ret) |
147 | goto out; |
148 | } |
149 | data->powerdown_mode[chan->channel] = mode; |
150 | |
151 | out: |
152 | mutex_unlock(lock: &data->lock); |
153 | |
154 | return ret; |
155 | } |
156 | |
157 | static const struct iio_enum dac5571_powerdown_mode = { |
158 | .items = dac5571_powerdown_modes, |
159 | .num_items = ARRAY_SIZE(dac5571_powerdown_modes), |
160 | .get = dac5571_get_powerdown_mode, |
161 | .set = dac5571_set_powerdown_mode, |
162 | }; |
163 | |
164 | static ssize_t dac5571_read_powerdown(struct iio_dev *indio_dev, |
165 | uintptr_t private, |
166 | const struct iio_chan_spec *chan, |
167 | char *buf) |
168 | { |
169 | struct dac5571_data *data = iio_priv(indio_dev); |
170 | |
171 | return sysfs_emit(buf, fmt: "%d\n" , data->powerdown[chan->channel]); |
172 | } |
173 | |
174 | static ssize_t dac5571_write_powerdown(struct iio_dev *indio_dev, |
175 | uintptr_t private, |
176 | const struct iio_chan_spec *chan, |
177 | const char *buf, size_t len) |
178 | { |
179 | struct dac5571_data *data = iio_priv(indio_dev); |
180 | bool powerdown; |
181 | int ret; |
182 | |
183 | ret = kstrtobool(s: buf, res: &powerdown); |
184 | if (ret) |
185 | return ret; |
186 | |
187 | if (data->powerdown[chan->channel] == powerdown) |
188 | return len; |
189 | |
190 | mutex_lock(&data->lock); |
191 | if (powerdown) |
192 | ret = data->dac5571_pwrdwn(data, chan->channel, |
193 | DAC5571_POWERDOWN(data->powerdown_mode[chan->channel])); |
194 | else |
195 | ret = data->dac5571_cmd(data, chan->channel, |
196 | data->val[chan->channel]); |
197 | if (ret) |
198 | goto out; |
199 | |
200 | data->powerdown[chan->channel] = powerdown; |
201 | |
202 | out: |
203 | mutex_unlock(lock: &data->lock); |
204 | |
205 | return ret ? ret : len; |
206 | } |
207 | |
208 | |
209 | static const struct iio_chan_spec_ext_info dac5571_ext_info[] = { |
210 | { |
211 | .name = "powerdown" , |
212 | .read = dac5571_read_powerdown, |
213 | .write = dac5571_write_powerdown, |
214 | .shared = IIO_SEPARATE, |
215 | }, |
216 | IIO_ENUM("powerdown_mode" , IIO_SEPARATE, &dac5571_powerdown_mode), |
217 | IIO_ENUM_AVAILABLE("powerdown_mode" , IIO_SHARED_BY_TYPE, &dac5571_powerdown_mode), |
218 | {}, |
219 | }; |
220 | |
221 | #define dac5571_CHANNEL(chan, name) { \ |
222 | .type = IIO_VOLTAGE, \ |
223 | .channel = (chan), \ |
224 | .address = (chan), \ |
225 | .indexed = true, \ |
226 | .output = true, \ |
227 | .datasheet_name = name, \ |
228 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ |
229 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ |
230 | .ext_info = dac5571_ext_info, \ |
231 | } |
232 | |
233 | static const struct iio_chan_spec dac5571_channels[] = { |
234 | dac5571_CHANNEL(0, "A" ), |
235 | dac5571_CHANNEL(1, "B" ), |
236 | dac5571_CHANNEL(2, "C" ), |
237 | dac5571_CHANNEL(3, "D" ), |
238 | }; |
239 | |
240 | static int dac5571_read_raw(struct iio_dev *indio_dev, |
241 | struct iio_chan_spec const *chan, |
242 | int *val, int *val2, long mask) |
243 | { |
244 | struct dac5571_data *data = iio_priv(indio_dev); |
245 | int ret; |
246 | |
247 | switch (mask) { |
248 | case IIO_CHAN_INFO_RAW: |
249 | *val = data->val[chan->channel]; |
250 | return IIO_VAL_INT; |
251 | |
252 | case IIO_CHAN_INFO_SCALE: |
253 | ret = regulator_get_voltage(regulator: data->vref); |
254 | if (ret < 0) |
255 | return ret; |
256 | |
257 | *val = ret / 1000; |
258 | *val2 = data->spec->resolution; |
259 | return IIO_VAL_FRACTIONAL_LOG2; |
260 | |
261 | default: |
262 | return -EINVAL; |
263 | } |
264 | } |
265 | |
266 | static int dac5571_write_raw(struct iio_dev *indio_dev, |
267 | struct iio_chan_spec const *chan, |
268 | int val, int val2, long mask) |
269 | { |
270 | struct dac5571_data *data = iio_priv(indio_dev); |
271 | int ret; |
272 | |
273 | switch (mask) { |
274 | case IIO_CHAN_INFO_RAW: |
275 | if (data->val[chan->channel] == val) |
276 | return 0; |
277 | |
278 | if (val >= (1 << data->spec->resolution) || val < 0) |
279 | return -EINVAL; |
280 | |
281 | if (data->powerdown[chan->channel]) |
282 | return -EBUSY; |
283 | |
284 | mutex_lock(&data->lock); |
285 | ret = data->dac5571_cmd(data, chan->channel, val); |
286 | if (ret == 0) |
287 | data->val[chan->channel] = val; |
288 | mutex_unlock(lock: &data->lock); |
289 | return ret; |
290 | |
291 | default: |
292 | return -EINVAL; |
293 | } |
294 | } |
295 | |
296 | static int dac5571_write_raw_get_fmt(struct iio_dev *indio_dev, |
297 | struct iio_chan_spec const *chan, |
298 | long mask) |
299 | { |
300 | return IIO_VAL_INT; |
301 | } |
302 | |
303 | static const struct iio_info dac5571_info = { |
304 | .read_raw = dac5571_read_raw, |
305 | .write_raw = dac5571_write_raw, |
306 | .write_raw_get_fmt = dac5571_write_raw_get_fmt, |
307 | }; |
308 | |
309 | static int dac5571_probe(struct i2c_client *client) |
310 | { |
311 | const struct i2c_device_id *id = i2c_client_get_device_id(client); |
312 | struct device *dev = &client->dev; |
313 | const struct dac5571_spec *spec; |
314 | struct dac5571_data *data; |
315 | struct iio_dev *indio_dev; |
316 | int ret, i; |
317 | |
318 | indio_dev = devm_iio_device_alloc(parent: dev, sizeof_priv: sizeof(*data)); |
319 | if (!indio_dev) |
320 | return -ENOMEM; |
321 | |
322 | data = iio_priv(indio_dev); |
323 | i2c_set_clientdata(client, data: indio_dev); |
324 | data->client = client; |
325 | |
326 | indio_dev->info = &dac5571_info; |
327 | indio_dev->name = id->name; |
328 | indio_dev->modes = INDIO_DIRECT_MODE; |
329 | indio_dev->channels = dac5571_channels; |
330 | |
331 | spec = i2c_get_match_data(client); |
332 | |
333 | indio_dev->num_channels = spec->num_channels; |
334 | data->spec = spec; |
335 | |
336 | data->vref = devm_regulator_get(dev, id: "vref" ); |
337 | if (IS_ERR(ptr: data->vref)) |
338 | return PTR_ERR(ptr: data->vref); |
339 | |
340 | ret = regulator_enable(regulator: data->vref); |
341 | if (ret < 0) |
342 | return ret; |
343 | |
344 | mutex_init(&data->lock); |
345 | |
346 | switch (spec->num_channels) { |
347 | case 1: |
348 | data->dac5571_cmd = dac5571_cmd_single; |
349 | data->dac5571_pwrdwn = dac5571_pwrdwn_single; |
350 | break; |
351 | case 4: |
352 | data->dac5571_cmd = dac5571_cmd_quad; |
353 | data->dac5571_pwrdwn = dac5571_pwrdwn_quad; |
354 | break; |
355 | default: |
356 | ret = -EINVAL; |
357 | goto err; |
358 | } |
359 | |
360 | for (i = 0; i < spec->num_channels; i++) { |
361 | ret = data->dac5571_cmd(data, i, 0); |
362 | if (ret) { |
363 | dev_err(dev, "failed to initialize channel %d to 0\n" , i); |
364 | goto err; |
365 | } |
366 | } |
367 | |
368 | ret = iio_device_register(indio_dev); |
369 | if (ret) |
370 | goto err; |
371 | |
372 | return 0; |
373 | |
374 | err: |
375 | regulator_disable(regulator: data->vref); |
376 | return ret; |
377 | } |
378 | |
379 | static void dac5571_remove(struct i2c_client *i2c) |
380 | { |
381 | struct iio_dev *indio_dev = i2c_get_clientdata(client: i2c); |
382 | struct dac5571_data *data = iio_priv(indio_dev); |
383 | |
384 | iio_device_unregister(indio_dev); |
385 | regulator_disable(regulator: data->vref); |
386 | } |
387 | |
388 | static const struct of_device_id dac5571_of_id[] = { |
389 | {.compatible = "ti,dac121c081" , .data = &dac5571_spec[single_12bit] }, |
390 | {.compatible = "ti,dac5571" , .data = &dac5571_spec[single_8bit] }, |
391 | {.compatible = "ti,dac6571" , .data = &dac5571_spec[single_10bit] }, |
392 | {.compatible = "ti,dac7571" , .data = &dac5571_spec[single_12bit] }, |
393 | {.compatible = "ti,dac5574" , .data = &dac5571_spec[quad_8bit] }, |
394 | {.compatible = "ti,dac6574" , .data = &dac5571_spec[quad_10bit] }, |
395 | {.compatible = "ti,dac7574" , .data = &dac5571_spec[quad_12bit] }, |
396 | {.compatible = "ti,dac5573" , .data = &dac5571_spec[quad_8bit] }, |
397 | {.compatible = "ti,dac6573" , .data = &dac5571_spec[quad_10bit] }, |
398 | {.compatible = "ti,dac7573" , .data = &dac5571_spec[quad_12bit] }, |
399 | {} |
400 | }; |
401 | MODULE_DEVICE_TABLE(of, dac5571_of_id); |
402 | |
403 | static const struct i2c_device_id dac5571_id[] = { |
404 | {"dac121c081" , (kernel_ulong_t)&dac5571_spec[single_12bit] }, |
405 | {"dac5571" , (kernel_ulong_t)&dac5571_spec[single_8bit] }, |
406 | {"dac6571" , (kernel_ulong_t)&dac5571_spec[single_10bit] }, |
407 | {"dac7571" , (kernel_ulong_t)&dac5571_spec[single_12bit] }, |
408 | {"dac5574" , (kernel_ulong_t)&dac5571_spec[quad_8bit] }, |
409 | {"dac6574" , (kernel_ulong_t)&dac5571_spec[quad_10bit] }, |
410 | {"dac7574" , (kernel_ulong_t)&dac5571_spec[quad_12bit] }, |
411 | {"dac5573" , (kernel_ulong_t)&dac5571_spec[quad_8bit] }, |
412 | {"dac6573" , (kernel_ulong_t)&dac5571_spec[quad_10bit] }, |
413 | {"dac7573" , (kernel_ulong_t)&dac5571_spec[quad_12bit] }, |
414 | {} |
415 | }; |
416 | MODULE_DEVICE_TABLE(i2c, dac5571_id); |
417 | |
418 | static struct i2c_driver dac5571_driver = { |
419 | .driver = { |
420 | .name = "ti-dac5571" , |
421 | .of_match_table = dac5571_of_id, |
422 | }, |
423 | .probe = dac5571_probe, |
424 | .remove = dac5571_remove, |
425 | .id_table = dac5571_id, |
426 | }; |
427 | module_i2c_driver(dac5571_driver); |
428 | |
429 | MODULE_AUTHOR("Sean Nyekjaer <sean@geanix.dk>" ); |
430 | MODULE_DESCRIPTION("Texas Instruments 8/10/12-bit 1/4-channel DAC driver" ); |
431 | MODULE_LICENSE("GPL v2" ); |
432 | |