1 | // SPDX-License-Identifier: GPL-2.0-only |
---|---|
2 | /* |
3 | * AD5024, AD5025, AD5044, AD5045, AD5064, AD5064-1, AD5065, AD5625, AD5625R, |
4 | * AD5627, AD5627R, AD5628, AD5629R, AD5645R, AD5647R, AD5648, AD5665, AD5665R, |
5 | * AD5666, AD5667, AD5667R, AD5668, AD5669R, LTC2606, LTC2607, LTC2609, LTC2616, |
6 | * LTC2617, LTC2619, LTC2626, LTC2627, LTC2629, LTC2631, LTC2633, LTC2635 |
7 | * Digital to analog converters driver |
8 | * |
9 | * Copyright 2011 Analog Devices Inc. |
10 | */ |
11 | |
12 | #include <linux/device.h> |
13 | #include <linux/err.h> |
14 | #include <linux/module.h> |
15 | #include <linux/kernel.h> |
16 | #include <linux/spi/spi.h> |
17 | #include <linux/i2c.h> |
18 | #include <linux/slab.h> |
19 | #include <linux/sysfs.h> |
20 | #include <linux/regulator/consumer.h> |
21 | #include <asm/unaligned.h> |
22 | |
23 | #include <linux/iio/iio.h> |
24 | #include <linux/iio/sysfs.h> |
25 | |
26 | #define AD5064_MAX_DAC_CHANNELS 8 |
27 | #define AD5064_MAX_VREFS 4 |
28 | |
29 | #define AD5064_ADDR(x) ((x) << 20) |
30 | #define AD5064_CMD(x) ((x) << 24) |
31 | |
32 | #define AD5064_ADDR_ALL_DAC 0xF |
33 | |
34 | #define AD5064_CMD_WRITE_INPUT_N 0x0 |
35 | #define AD5064_CMD_UPDATE_DAC_N 0x1 |
36 | #define AD5064_CMD_WRITE_INPUT_N_UPDATE_ALL 0x2 |
37 | #define AD5064_CMD_WRITE_INPUT_N_UPDATE_N 0x3 |
38 | #define AD5064_CMD_POWERDOWN_DAC 0x4 |
39 | #define AD5064_CMD_CLEAR 0x5 |
40 | #define AD5064_CMD_LDAC_MASK 0x6 |
41 | #define AD5064_CMD_RESET 0x7 |
42 | #define AD5064_CMD_CONFIG 0x8 |
43 | |
44 | #define AD5064_CMD_RESET_V2 0x5 |
45 | #define AD5064_CMD_CONFIG_V2 0x7 |
46 | |
47 | #define AD5064_CONFIG_DAISY_CHAIN_ENABLE BIT(1) |
48 | #define AD5064_CONFIG_INT_VREF_ENABLE BIT(0) |
49 | |
50 | #define AD5064_LDAC_PWRDN_NONE 0x0 |
51 | #define AD5064_LDAC_PWRDN_1K 0x1 |
52 | #define AD5064_LDAC_PWRDN_100K 0x2 |
53 | #define AD5064_LDAC_PWRDN_3STATE 0x3 |
54 | |
55 | /** |
56 | * enum ad5064_regmap_type - Register layout variant |
57 | * @AD5064_REGMAP_ADI: Old Analog Devices register map layout |
58 | * @AD5064_REGMAP_ADI2: New Analog Devices register map layout |
59 | * @AD5064_REGMAP_LTC: LTC register map layout |
60 | */ |
61 | enum ad5064_regmap_type { |
62 | AD5064_REGMAP_ADI, |
63 | AD5064_REGMAP_ADI2, |
64 | AD5064_REGMAP_LTC, |
65 | }; |
66 | |
67 | /** |
68 | * struct ad5064_chip_info - chip specific information |
69 | * @shared_vref: whether the vref supply is shared between channels |
70 | * @internal_vref: internal reference voltage. 0 if the chip has no |
71 | * internal vref. |
72 | * @channels: channel specification |
73 | * @num_channels: number of channels |
74 | * @regmap_type: register map layout variant |
75 | */ |
76 | |
77 | struct ad5064_chip_info { |
78 | bool shared_vref; |
79 | unsigned long internal_vref; |
80 | const struct iio_chan_spec *channels; |
81 | unsigned int num_channels; |
82 | enum ad5064_regmap_type regmap_type; |
83 | }; |
84 | |
85 | struct ad5064_state; |
86 | |
87 | typedef int (*ad5064_write_func)(struct ad5064_state *st, unsigned int cmd, |
88 | unsigned int addr, unsigned int val); |
89 | |
90 | /** |
91 | * struct ad5064_state - driver instance specific data |
92 | * @dev: the device for this driver instance |
93 | * @chip_info: chip model specific constants, available modes etc |
94 | * @vref_reg: vref supply regulators |
95 | * @pwr_down: whether channel is powered down |
96 | * @pwr_down_mode: channel's current power down mode |
97 | * @dac_cache: current DAC raw value (chip does not support readback) |
98 | * @use_internal_vref: set to true if the internal reference voltage should be |
99 | * used. |
100 | * @write: register write callback |
101 | * @lock: maintain consistency between cached and dev state |
102 | * @data: i2c/spi transfer buffers |
103 | */ |
104 | |
105 | struct ad5064_state { |
106 | struct device *dev; |
107 | const struct ad5064_chip_info *chip_info; |
108 | struct regulator_bulk_data vref_reg[AD5064_MAX_VREFS]; |
109 | bool pwr_down[AD5064_MAX_DAC_CHANNELS]; |
110 | u8 pwr_down_mode[AD5064_MAX_DAC_CHANNELS]; |
111 | unsigned int dac_cache[AD5064_MAX_DAC_CHANNELS]; |
112 | bool use_internal_vref; |
113 | |
114 | ad5064_write_func write; |
115 | struct mutex lock; |
116 | |
117 | /* |
118 | * DMA (thus cache coherency maintenance) may require the |
119 | * transfer buffers to live in their own cache lines. |
120 | */ |
121 | union { |
122 | u8 i2c[3]; |
123 | __be32 spi; |
124 | } data __aligned(IIO_DMA_MINALIGN); |
125 | }; |
126 | |
127 | enum ad5064_type { |
128 | ID_AD5024, |
129 | ID_AD5025, |
130 | ID_AD5044, |
131 | ID_AD5045, |
132 | ID_AD5064, |
133 | ID_AD5064_1, |
134 | ID_AD5065, |
135 | ID_AD5625, |
136 | ID_AD5625R_1V25, |
137 | ID_AD5625R_2V5, |
138 | ID_AD5627, |
139 | ID_AD5627R_1V25, |
140 | ID_AD5627R_2V5, |
141 | ID_AD5628_1, |
142 | ID_AD5628_2, |
143 | ID_AD5629_1, |
144 | ID_AD5629_2, |
145 | ID_AD5645R_1V25, |
146 | ID_AD5645R_2V5, |
147 | ID_AD5647R_1V25, |
148 | ID_AD5647R_2V5, |
149 | ID_AD5648_1, |
150 | ID_AD5648_2, |
151 | ID_AD5665, |
152 | ID_AD5665R_1V25, |
153 | ID_AD5665R_2V5, |
154 | ID_AD5666_1, |
155 | ID_AD5666_2, |
156 | ID_AD5667, |
157 | ID_AD5667R_1V25, |
158 | ID_AD5667R_2V5, |
159 | ID_AD5668_1, |
160 | ID_AD5668_2, |
161 | ID_AD5669_1, |
162 | ID_AD5669_2, |
163 | ID_LTC2606, |
164 | ID_LTC2607, |
165 | ID_LTC2609, |
166 | ID_LTC2616, |
167 | ID_LTC2617, |
168 | ID_LTC2619, |
169 | ID_LTC2626, |
170 | ID_LTC2627, |
171 | ID_LTC2629, |
172 | ID_LTC2631_L12, |
173 | ID_LTC2631_H12, |
174 | ID_LTC2631_L10, |
175 | ID_LTC2631_H10, |
176 | ID_LTC2631_L8, |
177 | ID_LTC2631_H8, |
178 | ID_LTC2633_L12, |
179 | ID_LTC2633_H12, |
180 | ID_LTC2633_L10, |
181 | ID_LTC2633_H10, |
182 | ID_LTC2633_L8, |
183 | ID_LTC2633_H8, |
184 | ID_LTC2635_L12, |
185 | ID_LTC2635_H12, |
186 | ID_LTC2635_L10, |
187 | ID_LTC2635_H10, |
188 | ID_LTC2635_L8, |
189 | ID_LTC2635_H8, |
190 | }; |
191 | |
192 | static int ad5064_write(struct ad5064_state *st, unsigned int cmd, |
193 | unsigned int addr, unsigned int val, unsigned int shift) |
194 | { |
195 | val <<= shift; |
196 | |
197 | return st->write(st, cmd, addr, val); |
198 | } |
199 | |
200 | static int ad5064_sync_powerdown_mode(struct ad5064_state *st, |
201 | const struct iio_chan_spec *chan) |
202 | { |
203 | unsigned int val, address; |
204 | unsigned int shift; |
205 | int ret; |
206 | |
207 | if (st->chip_info->regmap_type == AD5064_REGMAP_LTC) { |
208 | val = 0; |
209 | address = chan->address; |
210 | } else { |
211 | if (st->chip_info->regmap_type == AD5064_REGMAP_ADI2) |
212 | shift = 4; |
213 | else |
214 | shift = 8; |
215 | |
216 | val = (0x1 << chan->address); |
217 | address = 0; |
218 | |
219 | if (st->pwr_down[chan->channel]) |
220 | val |= st->pwr_down_mode[chan->channel] << shift; |
221 | } |
222 | |
223 | ret = ad5064_write(st, AD5064_CMD_POWERDOWN_DAC, addr: address, val, shift: 0); |
224 | |
225 | return ret; |
226 | } |
227 | |
228 | static const char * const ad5064_powerdown_modes[] = { |
229 | "1kohm_to_gnd", |
230 | "100kohm_to_gnd", |
231 | "three_state", |
232 | }; |
233 | |
234 | static const char * const ltc2617_powerdown_modes[] = { |
235 | "90kohm_to_gnd", |
236 | }; |
237 | |
238 | static int ad5064_get_powerdown_mode(struct iio_dev *indio_dev, |
239 | const struct iio_chan_spec *chan) |
240 | { |
241 | struct ad5064_state *st = iio_priv(indio_dev); |
242 | |
243 | return st->pwr_down_mode[chan->channel] - 1; |
244 | } |
245 | |
246 | static int ad5064_set_powerdown_mode(struct iio_dev *indio_dev, |
247 | const struct iio_chan_spec *chan, unsigned int mode) |
248 | { |
249 | struct ad5064_state *st = iio_priv(indio_dev); |
250 | int ret; |
251 | |
252 | mutex_lock(&st->lock); |
253 | st->pwr_down_mode[chan->channel] = mode + 1; |
254 | |
255 | ret = ad5064_sync_powerdown_mode(st, chan); |
256 | mutex_unlock(lock: &st->lock); |
257 | |
258 | return ret; |
259 | } |
260 | |
261 | static const struct iio_enum ad5064_powerdown_mode_enum = { |
262 | .items = ad5064_powerdown_modes, |
263 | .num_items = ARRAY_SIZE(ad5064_powerdown_modes), |
264 | .get = ad5064_get_powerdown_mode, |
265 | .set = ad5064_set_powerdown_mode, |
266 | }; |
267 | |
268 | static const struct iio_enum ltc2617_powerdown_mode_enum = { |
269 | .items = ltc2617_powerdown_modes, |
270 | .num_items = ARRAY_SIZE(ltc2617_powerdown_modes), |
271 | .get = ad5064_get_powerdown_mode, |
272 | .set = ad5064_set_powerdown_mode, |
273 | }; |
274 | |
275 | static ssize_t ad5064_read_dac_powerdown(struct iio_dev *indio_dev, |
276 | uintptr_t private, const struct iio_chan_spec *chan, char *buf) |
277 | { |
278 | struct ad5064_state *st = iio_priv(indio_dev); |
279 | |
280 | return sysfs_emit(buf, fmt: "%d\n", st->pwr_down[chan->channel]); |
281 | } |
282 | |
283 | static ssize_t ad5064_write_dac_powerdown(struct iio_dev *indio_dev, |
284 | uintptr_t private, const struct iio_chan_spec *chan, const char *buf, |
285 | size_t len) |
286 | { |
287 | struct ad5064_state *st = iio_priv(indio_dev); |
288 | bool pwr_down; |
289 | int ret; |
290 | |
291 | ret = kstrtobool(s: buf, res: &pwr_down); |
292 | if (ret) |
293 | return ret; |
294 | |
295 | mutex_lock(&st->lock); |
296 | st->pwr_down[chan->channel] = pwr_down; |
297 | |
298 | ret = ad5064_sync_powerdown_mode(st, chan); |
299 | mutex_unlock(lock: &st->lock); |
300 | return ret ? ret : len; |
301 | } |
302 | |
303 | static int ad5064_get_vref(struct ad5064_state *st, |
304 | struct iio_chan_spec const *chan) |
305 | { |
306 | unsigned int i; |
307 | |
308 | if (st->use_internal_vref) |
309 | return st->chip_info->internal_vref; |
310 | |
311 | i = st->chip_info->shared_vref ? 0 : chan->channel; |
312 | return regulator_get_voltage(regulator: st->vref_reg[i].consumer); |
313 | } |
314 | |
315 | static int ad5064_read_raw(struct iio_dev *indio_dev, |
316 | struct iio_chan_spec const *chan, |
317 | int *val, |
318 | int *val2, |
319 | long m) |
320 | { |
321 | struct ad5064_state *st = iio_priv(indio_dev); |
322 | int scale_uv; |
323 | |
324 | switch (m) { |
325 | case IIO_CHAN_INFO_RAW: |
326 | *val = st->dac_cache[chan->channel]; |
327 | return IIO_VAL_INT; |
328 | case IIO_CHAN_INFO_SCALE: |
329 | scale_uv = ad5064_get_vref(st, chan); |
330 | if (scale_uv < 0) |
331 | return scale_uv; |
332 | |
333 | *val = scale_uv / 1000; |
334 | *val2 = chan->scan_type.realbits; |
335 | return IIO_VAL_FRACTIONAL_LOG2; |
336 | default: |
337 | break; |
338 | } |
339 | return -EINVAL; |
340 | } |
341 | |
342 | static int ad5064_write_raw(struct iio_dev *indio_dev, |
343 | struct iio_chan_spec const *chan, int val, int val2, long mask) |
344 | { |
345 | struct ad5064_state *st = iio_priv(indio_dev); |
346 | int ret; |
347 | |
348 | switch (mask) { |
349 | case IIO_CHAN_INFO_RAW: |
350 | if (val >= (1 << chan->scan_type.realbits) || val < 0) |
351 | return -EINVAL; |
352 | |
353 | mutex_lock(&st->lock); |
354 | ret = ad5064_write(st, AD5064_CMD_WRITE_INPUT_N_UPDATE_N, |
355 | addr: chan->address, val, shift: chan->scan_type.shift); |
356 | if (ret == 0) |
357 | st->dac_cache[chan->channel] = val; |
358 | mutex_unlock(lock: &st->lock); |
359 | break; |
360 | default: |
361 | ret = -EINVAL; |
362 | } |
363 | |
364 | return ret; |
365 | } |
366 | |
367 | static const struct iio_info ad5064_info = { |
368 | .read_raw = ad5064_read_raw, |
369 | .write_raw = ad5064_write_raw, |
370 | }; |
371 | |
372 | static const struct iio_chan_spec_ext_info ad5064_ext_info[] = { |
373 | { |
374 | .name = "powerdown", |
375 | .read = ad5064_read_dac_powerdown, |
376 | .write = ad5064_write_dac_powerdown, |
377 | .shared = IIO_SEPARATE, |
378 | }, |
379 | IIO_ENUM("powerdown_mode", IIO_SEPARATE, &ad5064_powerdown_mode_enum), |
380 | IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE, &ad5064_powerdown_mode_enum), |
381 | { }, |
382 | }; |
383 | |
384 | static const struct iio_chan_spec_ext_info ltc2617_ext_info[] = { |
385 | { |
386 | .name = "powerdown", |
387 | .read = ad5064_read_dac_powerdown, |
388 | .write = ad5064_write_dac_powerdown, |
389 | .shared = IIO_SEPARATE, |
390 | }, |
391 | IIO_ENUM("powerdown_mode", IIO_SEPARATE, <c2617_powerdown_mode_enum), |
392 | IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE, <c2617_powerdown_mode_enum), |
393 | { }, |
394 | }; |
395 | |
396 | #define AD5064_CHANNEL(chan, addr, bits, _shift, _ext_info) { \ |
397 | .type = IIO_VOLTAGE, \ |
398 | .indexed = 1, \ |
399 | .output = 1, \ |
400 | .channel = (chan), \ |
401 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ |
402 | BIT(IIO_CHAN_INFO_SCALE), \ |
403 | .address = addr, \ |
404 | .scan_type = { \ |
405 | .sign = 'u', \ |
406 | .realbits = (bits), \ |
407 | .storagebits = 16, \ |
408 | .shift = (_shift), \ |
409 | }, \ |
410 | .ext_info = (_ext_info), \ |
411 | } |
412 | |
413 | #define DECLARE_AD5064_CHANNELS(name, bits, shift, ext_info) \ |
414 | const struct iio_chan_spec name[] = { \ |
415 | AD5064_CHANNEL(0, 0, bits, shift, ext_info), \ |
416 | AD5064_CHANNEL(1, 1, bits, shift, ext_info), \ |
417 | AD5064_CHANNEL(2, 2, bits, shift, ext_info), \ |
418 | AD5064_CHANNEL(3, 3, bits, shift, ext_info), \ |
419 | AD5064_CHANNEL(4, 4, bits, shift, ext_info), \ |
420 | AD5064_CHANNEL(5, 5, bits, shift, ext_info), \ |
421 | AD5064_CHANNEL(6, 6, bits, shift, ext_info), \ |
422 | AD5064_CHANNEL(7, 7, bits, shift, ext_info), \ |
423 | } |
424 | |
425 | #define DECLARE_AD5065_CHANNELS(name, bits, shift, ext_info) \ |
426 | const struct iio_chan_spec name[] = { \ |
427 | AD5064_CHANNEL(0, 0, bits, shift, ext_info), \ |
428 | AD5064_CHANNEL(1, 3, bits, shift, ext_info), \ |
429 | } |
430 | |
431 | static DECLARE_AD5064_CHANNELS(ad5024_channels, 12, 8, ad5064_ext_info); |
432 | static DECLARE_AD5064_CHANNELS(ad5044_channels, 14, 6, ad5064_ext_info); |
433 | static DECLARE_AD5064_CHANNELS(ad5064_channels, 16, 4, ad5064_ext_info); |
434 | |
435 | static DECLARE_AD5065_CHANNELS(ad5025_channels, 12, 8, ad5064_ext_info); |
436 | static DECLARE_AD5065_CHANNELS(ad5045_channels, 14, 6, ad5064_ext_info); |
437 | static DECLARE_AD5065_CHANNELS(ad5065_channels, 16, 4, ad5064_ext_info); |
438 | |
439 | static DECLARE_AD5064_CHANNELS(ad5629_channels, 12, 4, ad5064_ext_info); |
440 | static DECLARE_AD5064_CHANNELS(ad5645_channels, 14, 2, ad5064_ext_info); |
441 | static DECLARE_AD5064_CHANNELS(ad5669_channels, 16, 0, ad5064_ext_info); |
442 | |
443 | static DECLARE_AD5064_CHANNELS(ltc2607_channels, 16, 0, ltc2617_ext_info); |
444 | static DECLARE_AD5064_CHANNELS(ltc2617_channels, 14, 2, ltc2617_ext_info); |
445 | static DECLARE_AD5064_CHANNELS(ltc2627_channels, 12, 4, ltc2617_ext_info); |
446 | #define ltc2631_12_channels ltc2627_channels |
447 | static DECLARE_AD5064_CHANNELS(ltc2631_10_channels, 10, 6, ltc2617_ext_info); |
448 | static DECLARE_AD5064_CHANNELS(ltc2631_8_channels, 8, 8, ltc2617_ext_info); |
449 | |
450 | #define LTC2631_INFO(vref, pchannels, nchannels) \ |
451 | { \ |
452 | .shared_vref = true, \ |
453 | .internal_vref = vref, \ |
454 | .channels = pchannels, \ |
455 | .num_channels = nchannels, \ |
456 | .regmap_type = AD5064_REGMAP_LTC, \ |
457 | } |
458 | |
459 | |
460 | static const struct ad5064_chip_info ad5064_chip_info_tbl[] = { |
461 | [ID_AD5024] = { |
462 | .shared_vref = false, |
463 | .channels = ad5024_channels, |
464 | .num_channels = 4, |
465 | .regmap_type = AD5064_REGMAP_ADI, |
466 | }, |
467 | [ID_AD5025] = { |
468 | .shared_vref = false, |
469 | .channels = ad5025_channels, |
470 | .num_channels = 2, |
471 | .regmap_type = AD5064_REGMAP_ADI, |
472 | }, |
473 | [ID_AD5044] = { |
474 | .shared_vref = false, |
475 | .channels = ad5044_channels, |
476 | .num_channels = 4, |
477 | .regmap_type = AD5064_REGMAP_ADI, |
478 | }, |
479 | [ID_AD5045] = { |
480 | .shared_vref = false, |
481 | .channels = ad5045_channels, |
482 | .num_channels = 2, |
483 | .regmap_type = AD5064_REGMAP_ADI, |
484 | }, |
485 | [ID_AD5064] = { |
486 | .shared_vref = false, |
487 | .channels = ad5064_channels, |
488 | .num_channels = 4, |
489 | .regmap_type = AD5064_REGMAP_ADI, |
490 | }, |
491 | [ID_AD5064_1] = { |
492 | .shared_vref = true, |
493 | .channels = ad5064_channels, |
494 | .num_channels = 4, |
495 | .regmap_type = AD5064_REGMAP_ADI, |
496 | }, |
497 | [ID_AD5065] = { |
498 | .shared_vref = false, |
499 | .channels = ad5065_channels, |
500 | .num_channels = 2, |
501 | .regmap_type = AD5064_REGMAP_ADI, |
502 | }, |
503 | [ID_AD5625] = { |
504 | .shared_vref = true, |
505 | .channels = ad5629_channels, |
506 | .num_channels = 4, |
507 | .regmap_type = AD5064_REGMAP_ADI2 |
508 | }, |
509 | [ID_AD5625R_1V25] = { |
510 | .shared_vref = true, |
511 | .internal_vref = 1250000, |
512 | .channels = ad5629_channels, |
513 | .num_channels = 4, |
514 | .regmap_type = AD5064_REGMAP_ADI2 |
515 | }, |
516 | [ID_AD5625R_2V5] = { |
517 | .shared_vref = true, |
518 | .internal_vref = 2500000, |
519 | .channels = ad5629_channels, |
520 | .num_channels = 4, |
521 | .regmap_type = AD5064_REGMAP_ADI2 |
522 | }, |
523 | [ID_AD5627] = { |
524 | .shared_vref = true, |
525 | .channels = ad5629_channels, |
526 | .num_channels = 2, |
527 | .regmap_type = AD5064_REGMAP_ADI2 |
528 | }, |
529 | [ID_AD5627R_1V25] = { |
530 | .shared_vref = true, |
531 | .internal_vref = 1250000, |
532 | .channels = ad5629_channels, |
533 | .num_channels = 2, |
534 | .regmap_type = AD5064_REGMAP_ADI2 |
535 | }, |
536 | [ID_AD5627R_2V5] = { |
537 | .shared_vref = true, |
538 | .internal_vref = 2500000, |
539 | .channels = ad5629_channels, |
540 | .num_channels = 2, |
541 | .regmap_type = AD5064_REGMAP_ADI2 |
542 | }, |
543 | [ID_AD5628_1] = { |
544 | .shared_vref = true, |
545 | .internal_vref = 2500000, |
546 | .channels = ad5024_channels, |
547 | .num_channels = 8, |
548 | .regmap_type = AD5064_REGMAP_ADI, |
549 | }, |
550 | [ID_AD5628_2] = { |
551 | .shared_vref = true, |
552 | .internal_vref = 5000000, |
553 | .channels = ad5024_channels, |
554 | .num_channels = 8, |
555 | .regmap_type = AD5064_REGMAP_ADI, |
556 | }, |
557 | [ID_AD5629_1] = { |
558 | .shared_vref = true, |
559 | .internal_vref = 2500000, |
560 | .channels = ad5629_channels, |
561 | .num_channels = 8, |
562 | .regmap_type = AD5064_REGMAP_ADI, |
563 | }, |
564 | [ID_AD5629_2] = { |
565 | .shared_vref = true, |
566 | .internal_vref = 5000000, |
567 | .channels = ad5629_channels, |
568 | .num_channels = 8, |
569 | .regmap_type = AD5064_REGMAP_ADI, |
570 | }, |
571 | [ID_AD5645R_1V25] = { |
572 | .shared_vref = true, |
573 | .internal_vref = 1250000, |
574 | .channels = ad5645_channels, |
575 | .num_channels = 4, |
576 | .regmap_type = AD5064_REGMAP_ADI2 |
577 | }, |
578 | [ID_AD5645R_2V5] = { |
579 | .shared_vref = true, |
580 | .internal_vref = 2500000, |
581 | .channels = ad5645_channels, |
582 | .num_channels = 4, |
583 | .regmap_type = AD5064_REGMAP_ADI2 |
584 | }, |
585 | [ID_AD5647R_1V25] = { |
586 | .shared_vref = true, |
587 | .internal_vref = 1250000, |
588 | .channels = ad5645_channels, |
589 | .num_channels = 2, |
590 | .regmap_type = AD5064_REGMAP_ADI2 |
591 | }, |
592 | [ID_AD5647R_2V5] = { |
593 | .shared_vref = true, |
594 | .internal_vref = 2500000, |
595 | .channels = ad5645_channels, |
596 | .num_channels = 2, |
597 | .regmap_type = AD5064_REGMAP_ADI2 |
598 | }, |
599 | [ID_AD5648_1] = { |
600 | .shared_vref = true, |
601 | .internal_vref = 2500000, |
602 | .channels = ad5044_channels, |
603 | .num_channels = 8, |
604 | .regmap_type = AD5064_REGMAP_ADI, |
605 | }, |
606 | [ID_AD5648_2] = { |
607 | .shared_vref = true, |
608 | .internal_vref = 5000000, |
609 | .channels = ad5044_channels, |
610 | .num_channels = 8, |
611 | .regmap_type = AD5064_REGMAP_ADI, |
612 | }, |
613 | [ID_AD5665] = { |
614 | .shared_vref = true, |
615 | .channels = ad5669_channels, |
616 | .num_channels = 4, |
617 | .regmap_type = AD5064_REGMAP_ADI2 |
618 | }, |
619 | [ID_AD5665R_1V25] = { |
620 | .shared_vref = true, |
621 | .internal_vref = 1250000, |
622 | .channels = ad5669_channels, |
623 | .num_channels = 4, |
624 | .regmap_type = AD5064_REGMAP_ADI2 |
625 | }, |
626 | [ID_AD5665R_2V5] = { |
627 | .shared_vref = true, |
628 | .internal_vref = 2500000, |
629 | .channels = ad5669_channels, |
630 | .num_channels = 4, |
631 | .regmap_type = AD5064_REGMAP_ADI2 |
632 | }, |
633 | [ID_AD5666_1] = { |
634 | .shared_vref = true, |
635 | .internal_vref = 2500000, |
636 | .channels = ad5064_channels, |
637 | .num_channels = 4, |
638 | .regmap_type = AD5064_REGMAP_ADI, |
639 | }, |
640 | [ID_AD5666_2] = { |
641 | .shared_vref = true, |
642 | .internal_vref = 5000000, |
643 | .channels = ad5064_channels, |
644 | .num_channels = 4, |
645 | .regmap_type = AD5064_REGMAP_ADI, |
646 | }, |
647 | [ID_AD5667] = { |
648 | .shared_vref = true, |
649 | .channels = ad5669_channels, |
650 | .num_channels = 2, |
651 | .regmap_type = AD5064_REGMAP_ADI2 |
652 | }, |
653 | [ID_AD5667R_1V25] = { |
654 | .shared_vref = true, |
655 | .internal_vref = 1250000, |
656 | .channels = ad5669_channels, |
657 | .num_channels = 2, |
658 | .regmap_type = AD5064_REGMAP_ADI2 |
659 | }, |
660 | [ID_AD5667R_2V5] = { |
661 | .shared_vref = true, |
662 | .internal_vref = 2500000, |
663 | .channels = ad5669_channels, |
664 | .num_channels = 2, |
665 | .regmap_type = AD5064_REGMAP_ADI2 |
666 | }, |
667 | [ID_AD5668_1] = { |
668 | .shared_vref = true, |
669 | .internal_vref = 2500000, |
670 | .channels = ad5064_channels, |
671 | .num_channels = 8, |
672 | .regmap_type = AD5064_REGMAP_ADI, |
673 | }, |
674 | [ID_AD5668_2] = { |
675 | .shared_vref = true, |
676 | .internal_vref = 5000000, |
677 | .channels = ad5064_channels, |
678 | .num_channels = 8, |
679 | .regmap_type = AD5064_REGMAP_ADI, |
680 | }, |
681 | [ID_AD5669_1] = { |
682 | .shared_vref = true, |
683 | .internal_vref = 2500000, |
684 | .channels = ad5669_channels, |
685 | .num_channels = 8, |
686 | .regmap_type = AD5064_REGMAP_ADI, |
687 | }, |
688 | [ID_AD5669_2] = { |
689 | .shared_vref = true, |
690 | .internal_vref = 5000000, |
691 | .channels = ad5669_channels, |
692 | .num_channels = 8, |
693 | .regmap_type = AD5064_REGMAP_ADI, |
694 | }, |
695 | [ID_LTC2606] = { |
696 | .shared_vref = true, |
697 | .internal_vref = 0, |
698 | .channels = ltc2607_channels, |
699 | .num_channels = 1, |
700 | .regmap_type = AD5064_REGMAP_LTC, |
701 | }, |
702 | [ID_LTC2607] = { |
703 | .shared_vref = true, |
704 | .internal_vref = 0, |
705 | .channels = ltc2607_channels, |
706 | .num_channels = 2, |
707 | .regmap_type = AD5064_REGMAP_LTC, |
708 | }, |
709 | [ID_LTC2609] = { |
710 | .shared_vref = false, |
711 | .internal_vref = 0, |
712 | .channels = ltc2607_channels, |
713 | .num_channels = 4, |
714 | .regmap_type = AD5064_REGMAP_LTC, |
715 | }, |
716 | [ID_LTC2616] = { |
717 | .shared_vref = true, |
718 | .internal_vref = 0, |
719 | .channels = ltc2617_channels, |
720 | .num_channels = 1, |
721 | .regmap_type = AD5064_REGMAP_LTC, |
722 | }, |
723 | [ID_LTC2617] = { |
724 | .shared_vref = true, |
725 | .internal_vref = 0, |
726 | .channels = ltc2617_channels, |
727 | .num_channels = 2, |
728 | .regmap_type = AD5064_REGMAP_LTC, |
729 | }, |
730 | [ID_LTC2619] = { |
731 | .shared_vref = false, |
732 | .internal_vref = 0, |
733 | .channels = ltc2617_channels, |
734 | .num_channels = 4, |
735 | .regmap_type = AD5064_REGMAP_LTC, |
736 | }, |
737 | [ID_LTC2626] = { |
738 | .shared_vref = true, |
739 | .internal_vref = 0, |
740 | .channels = ltc2627_channels, |
741 | .num_channels = 1, |
742 | .regmap_type = AD5064_REGMAP_LTC, |
743 | }, |
744 | [ID_LTC2627] = { |
745 | .shared_vref = true, |
746 | .internal_vref = 0, |
747 | .channels = ltc2627_channels, |
748 | .num_channels = 2, |
749 | .regmap_type = AD5064_REGMAP_LTC, |
750 | }, |
751 | [ID_LTC2629] = { |
752 | .shared_vref = false, |
753 | .internal_vref = 0, |
754 | .channels = ltc2627_channels, |
755 | .num_channels = 4, |
756 | .regmap_type = AD5064_REGMAP_LTC, |
757 | }, |
758 | [ID_LTC2631_L12] = LTC2631_INFO(2500000, ltc2631_12_channels, 1), |
759 | [ID_LTC2631_H12] = LTC2631_INFO(4096000, ltc2631_12_channels, 1), |
760 | [ID_LTC2631_L10] = LTC2631_INFO(2500000, ltc2631_10_channels, 1), |
761 | [ID_LTC2631_H10] = LTC2631_INFO(4096000, ltc2631_10_channels, 1), |
762 | [ID_LTC2631_L8] = LTC2631_INFO(2500000, ltc2631_8_channels, 1), |
763 | [ID_LTC2631_H8] = LTC2631_INFO(4096000, ltc2631_8_channels, 1), |
764 | [ID_LTC2633_L12] = LTC2631_INFO(2500000, ltc2631_12_channels, 2), |
765 | [ID_LTC2633_H12] = LTC2631_INFO(4096000, ltc2631_12_channels, 2), |
766 | [ID_LTC2633_L10] = LTC2631_INFO(2500000, ltc2631_10_channels, 2), |
767 | [ID_LTC2633_H10] = LTC2631_INFO(4096000, ltc2631_10_channels, 2), |
768 | [ID_LTC2633_L8] = LTC2631_INFO(2500000, ltc2631_8_channels, 2), |
769 | [ID_LTC2633_H8] = LTC2631_INFO(4096000, ltc2631_8_channels, 2), |
770 | [ID_LTC2635_L12] = LTC2631_INFO(2500000, ltc2631_12_channels, 4), |
771 | [ID_LTC2635_H12] = LTC2631_INFO(4096000, ltc2631_12_channels, 4), |
772 | [ID_LTC2635_L10] = LTC2631_INFO(2500000, ltc2631_10_channels, 4), |
773 | [ID_LTC2635_H10] = LTC2631_INFO(4096000, ltc2631_10_channels, 4), |
774 | [ID_LTC2635_L8] = LTC2631_INFO(2500000, ltc2631_8_channels, 4), |
775 | [ID_LTC2635_H8] = LTC2631_INFO(4096000, ltc2631_8_channels, 4), |
776 | }; |
777 | |
778 | static inline unsigned int ad5064_num_vref(struct ad5064_state *st) |
779 | { |
780 | return st->chip_info->shared_vref ? 1 : st->chip_info->num_channels; |
781 | } |
782 | |
783 | static const char * const ad5064_vref_names[] = { |
784 | "vrefA", |
785 | "vrefB", |
786 | "vrefC", |
787 | "vrefD", |
788 | }; |
789 | |
790 | static const char *ad5064_vref_name(struct ad5064_state *st, |
791 | unsigned int vref) |
792 | { |
793 | return st->chip_info->shared_vref ? "vref": ad5064_vref_names[vref]; |
794 | } |
795 | |
796 | static int ad5064_set_config(struct ad5064_state *st, unsigned int val) |
797 | { |
798 | unsigned int cmd; |
799 | |
800 | switch (st->chip_info->regmap_type) { |
801 | case AD5064_REGMAP_ADI2: |
802 | cmd = AD5064_CMD_CONFIG_V2; |
803 | break; |
804 | default: |
805 | cmd = AD5064_CMD_CONFIG; |
806 | break; |
807 | } |
808 | |
809 | return ad5064_write(st, cmd, addr: 0, val, shift: 0); |
810 | } |
811 | |
812 | static int ad5064_request_vref(struct ad5064_state *st, struct device *dev) |
813 | { |
814 | unsigned int i; |
815 | int ret; |
816 | |
817 | for (i = 0; i < ad5064_num_vref(st); ++i) |
818 | st->vref_reg[i].supply = ad5064_vref_name(st, vref: i); |
819 | |
820 | if (!st->chip_info->internal_vref) |
821 | return devm_regulator_bulk_get(dev, num_consumers: ad5064_num_vref(st), |
822 | consumers: st->vref_reg); |
823 | |
824 | /* |
825 | * This assumes that when the regulator has an internal VREF |
826 | * there is only one external VREF connection, which is |
827 | * currently the case for all supported devices. |
828 | */ |
829 | st->vref_reg[0].consumer = devm_regulator_get_optional(dev, id: "vref"); |
830 | if (!IS_ERR(ptr: st->vref_reg[0].consumer)) |
831 | return 0; |
832 | |
833 | ret = PTR_ERR(ptr: st->vref_reg[0].consumer); |
834 | if (ret != -ENODEV) |
835 | return ret; |
836 | |
837 | /* If no external regulator was supplied use the internal VREF */ |
838 | st->use_internal_vref = true; |
839 | ret = ad5064_set_config(st, AD5064_CONFIG_INT_VREF_ENABLE); |
840 | if (ret) |
841 | dev_err(dev, "Failed to enable internal vref: %d\n", ret); |
842 | |
843 | return ret; |
844 | } |
845 | |
846 | static void ad5064_bulk_reg_disable(void *data) |
847 | { |
848 | struct ad5064_state *st = data; |
849 | |
850 | regulator_bulk_disable(num_consumers: ad5064_num_vref(st), consumers: st->vref_reg); |
851 | } |
852 | |
853 | static int ad5064_probe(struct device *dev, enum ad5064_type type, |
854 | const char *name, ad5064_write_func write) |
855 | { |
856 | struct iio_dev *indio_dev; |
857 | struct ad5064_state *st; |
858 | unsigned int midscale; |
859 | unsigned int i; |
860 | int ret; |
861 | |
862 | indio_dev = devm_iio_device_alloc(parent: dev, sizeof_priv: sizeof(*st)); |
863 | if (indio_dev == NULL) |
864 | return -ENOMEM; |
865 | |
866 | st = iio_priv(indio_dev); |
867 | mutex_init(&st->lock); |
868 | |
869 | st->chip_info = &ad5064_chip_info_tbl[type]; |
870 | st->dev = dev; |
871 | st->write = write; |
872 | |
873 | ret = ad5064_request_vref(st, dev); |
874 | if (ret) |
875 | return ret; |
876 | |
877 | if (!st->use_internal_vref) { |
878 | ret = regulator_bulk_enable(num_consumers: ad5064_num_vref(st), consumers: st->vref_reg); |
879 | if (ret) |
880 | return ret; |
881 | |
882 | ret = devm_add_action_or_reset(dev, ad5064_bulk_reg_disable, st); |
883 | if (ret) |
884 | return ret; |
885 | } |
886 | |
887 | indio_dev->name = name; |
888 | indio_dev->info = &ad5064_info; |
889 | indio_dev->modes = INDIO_DIRECT_MODE; |
890 | indio_dev->channels = st->chip_info->channels; |
891 | indio_dev->num_channels = st->chip_info->num_channels; |
892 | |
893 | midscale = (1 << indio_dev->channels[0].scan_type.realbits) / 2; |
894 | |
895 | for (i = 0; i < st->chip_info->num_channels; ++i) { |
896 | st->pwr_down_mode[i] = AD5064_LDAC_PWRDN_1K; |
897 | st->dac_cache[i] = midscale; |
898 | } |
899 | |
900 | return devm_iio_device_register(dev, indio_dev); |
901 | } |
902 | |
903 | #if IS_ENABLED(CONFIG_SPI_MASTER) |
904 | |
905 | static int ad5064_spi_write(struct ad5064_state *st, unsigned int cmd, |
906 | unsigned int addr, unsigned int val) |
907 | { |
908 | struct spi_device *spi = to_spi_device(dev: st->dev); |
909 | |
910 | st->data.spi = cpu_to_be32(AD5064_CMD(cmd) | AD5064_ADDR(addr) | val); |
911 | return spi_write(spi, buf: &st->data.spi, len: sizeof(st->data.spi)); |
912 | } |
913 | |
914 | static int ad5064_spi_probe(struct spi_device *spi) |
915 | { |
916 | const struct spi_device_id *id = spi_get_device_id(sdev: spi); |
917 | |
918 | return ad5064_probe(dev: &spi->dev, type: id->driver_data, name: id->name, |
919 | write: ad5064_spi_write); |
920 | } |
921 | |
922 | static const struct spi_device_id ad5064_spi_ids[] = { |
923 | {"ad5024", ID_AD5024}, |
924 | {"ad5025", ID_AD5025}, |
925 | {"ad5044", ID_AD5044}, |
926 | {"ad5045", ID_AD5045}, |
927 | {"ad5064", ID_AD5064}, |
928 | {"ad5064-1", ID_AD5064_1}, |
929 | {"ad5065", ID_AD5065}, |
930 | {"ad5628-1", ID_AD5628_1}, |
931 | {"ad5628-2", ID_AD5628_2}, |
932 | {"ad5648-1", ID_AD5648_1}, |
933 | {"ad5648-2", ID_AD5648_2}, |
934 | {"ad5666-1", ID_AD5666_1}, |
935 | {"ad5666-2", ID_AD5666_2}, |
936 | {"ad5668-1", ID_AD5668_1}, |
937 | {"ad5668-2", ID_AD5668_2}, |
938 | {"ad5668-3", ID_AD5668_2}, /* similar enough to ad5668-2 */ |
939 | {} |
940 | }; |
941 | MODULE_DEVICE_TABLE(spi, ad5064_spi_ids); |
942 | |
943 | static struct spi_driver ad5064_spi_driver = { |
944 | .driver = { |
945 | .name = "ad5064", |
946 | }, |
947 | .probe = ad5064_spi_probe, |
948 | .id_table = ad5064_spi_ids, |
949 | }; |
950 | |
951 | static int __init ad5064_spi_register_driver(void) |
952 | { |
953 | return spi_register_driver(&ad5064_spi_driver); |
954 | } |
955 | |
956 | static void ad5064_spi_unregister_driver(void) |
957 | { |
958 | spi_unregister_driver(sdrv: &ad5064_spi_driver); |
959 | } |
960 | |
961 | #else |
962 | |
963 | static inline int ad5064_spi_register_driver(void) { return 0; } |
964 | static inline void ad5064_spi_unregister_driver(void) { } |
965 | |
966 | #endif |
967 | |
968 | #if IS_ENABLED(CONFIG_I2C) |
969 | |
970 | static int ad5064_i2c_write(struct ad5064_state *st, unsigned int cmd, |
971 | unsigned int addr, unsigned int val) |
972 | { |
973 | struct i2c_client *i2c = to_i2c_client(st->dev); |
974 | unsigned int cmd_shift; |
975 | int ret; |
976 | |
977 | switch (st->chip_info->regmap_type) { |
978 | case AD5064_REGMAP_ADI2: |
979 | cmd_shift = 3; |
980 | break; |
981 | default: |
982 | cmd_shift = 4; |
983 | break; |
984 | } |
985 | |
986 | st->data.i2c[0] = (cmd << cmd_shift) | addr; |
987 | put_unaligned_be16(val, p: &st->data.i2c[1]); |
988 | |
989 | ret = i2c_master_send(client: i2c, buf: st->data.i2c, count: 3); |
990 | if (ret < 0) |
991 | return ret; |
992 | |
993 | return 0; |
994 | } |
995 | |
996 | static int ad5064_i2c_probe(struct i2c_client *i2c) |
997 | { |
998 | const struct i2c_device_id *id = i2c_client_get_device_id(client: i2c); |
999 | return ad5064_probe(dev: &i2c->dev, type: id->driver_data, name: id->name, |
1000 | write: ad5064_i2c_write); |
1001 | } |
1002 | |
1003 | static const struct i2c_device_id ad5064_i2c_ids[] = { |
1004 | {"ad5625", ID_AD5625 }, |
1005 | {"ad5625r-1v25", ID_AD5625R_1V25 }, |
1006 | {"ad5625r-2v5", ID_AD5625R_2V5 }, |
1007 | {"ad5627", ID_AD5627 }, |
1008 | {"ad5627r-1v25", ID_AD5627R_1V25 }, |
1009 | {"ad5627r-2v5", ID_AD5627R_2V5 }, |
1010 | {"ad5629-1", ID_AD5629_1}, |
1011 | {"ad5629-2", ID_AD5629_2}, |
1012 | {"ad5629-3", ID_AD5629_2}, /* similar enough to ad5629-2 */ |
1013 | {"ad5645r-1v25", ID_AD5645R_1V25 }, |
1014 | {"ad5645r-2v5", ID_AD5645R_2V5 }, |
1015 | {"ad5665", ID_AD5665 }, |
1016 | {"ad5665r-1v25", ID_AD5665R_1V25 }, |
1017 | {"ad5665r-2v5", ID_AD5665R_2V5 }, |
1018 | {"ad5667", ID_AD5667 }, |
1019 | {"ad5667r-1v25", ID_AD5667R_1V25 }, |
1020 | {"ad5667r-2v5", ID_AD5667R_2V5 }, |
1021 | {"ad5669-1", ID_AD5669_1}, |
1022 | {"ad5669-2", ID_AD5669_2}, |
1023 | {"ad5669-3", ID_AD5669_2}, /* similar enough to ad5669-2 */ |
1024 | {"ltc2606", ID_LTC2606}, |
1025 | {"ltc2607", ID_LTC2607}, |
1026 | {"ltc2609", ID_LTC2609}, |
1027 | {"ltc2616", ID_LTC2616}, |
1028 | {"ltc2617", ID_LTC2617}, |
1029 | {"ltc2619", ID_LTC2619}, |
1030 | {"ltc2626", ID_LTC2626}, |
1031 | {"ltc2627", ID_LTC2627}, |
1032 | {"ltc2629", ID_LTC2629}, |
1033 | {"ltc2631-l12", ID_LTC2631_L12}, |
1034 | {"ltc2631-h12", ID_LTC2631_H12}, |
1035 | {"ltc2631-l10", ID_LTC2631_L10}, |
1036 | {"ltc2631-h10", ID_LTC2631_H10}, |
1037 | {"ltc2631-l8", ID_LTC2631_L8}, |
1038 | {"ltc2631-h8", ID_LTC2631_H8}, |
1039 | {"ltc2633-l12", ID_LTC2633_L12}, |
1040 | {"ltc2633-h12", ID_LTC2633_H12}, |
1041 | {"ltc2633-l10", ID_LTC2633_L10}, |
1042 | {"ltc2633-h10", ID_LTC2633_H10}, |
1043 | {"ltc2633-l8", ID_LTC2633_L8}, |
1044 | {"ltc2633-h8", ID_LTC2633_H8}, |
1045 | {"ltc2635-l12", ID_LTC2635_L12}, |
1046 | {"ltc2635-h12", ID_LTC2635_H12}, |
1047 | {"ltc2635-l10", ID_LTC2635_L10}, |
1048 | {"ltc2635-h10", ID_LTC2635_H10}, |
1049 | {"ltc2635-l8", ID_LTC2635_L8}, |
1050 | {"ltc2635-h8", ID_LTC2635_H8}, |
1051 | {} |
1052 | }; |
1053 | MODULE_DEVICE_TABLE(i2c, ad5064_i2c_ids); |
1054 | |
1055 | static struct i2c_driver ad5064_i2c_driver = { |
1056 | .driver = { |
1057 | .name = "ad5064", |
1058 | }, |
1059 | .probe = ad5064_i2c_probe, |
1060 | .id_table = ad5064_i2c_ids, |
1061 | }; |
1062 | |
1063 | static int __init ad5064_i2c_register_driver(void) |
1064 | { |
1065 | return i2c_add_driver(&ad5064_i2c_driver); |
1066 | } |
1067 | |
1068 | static void __exit ad5064_i2c_unregister_driver(void) |
1069 | { |
1070 | i2c_del_driver(driver: &ad5064_i2c_driver); |
1071 | } |
1072 | |
1073 | #else |
1074 | |
1075 | static inline int ad5064_i2c_register_driver(void) { return 0; } |
1076 | static inline void ad5064_i2c_unregister_driver(void) { } |
1077 | |
1078 | #endif |
1079 | |
1080 | static int __init ad5064_init(void) |
1081 | { |
1082 | int ret; |
1083 | |
1084 | ret = ad5064_spi_register_driver(); |
1085 | if (ret) |
1086 | return ret; |
1087 | |
1088 | ret = ad5064_i2c_register_driver(); |
1089 | if (ret) { |
1090 | ad5064_spi_unregister_driver(); |
1091 | return ret; |
1092 | } |
1093 | |
1094 | return 0; |
1095 | } |
1096 | module_init(ad5064_init); |
1097 | |
1098 | static void __exit ad5064_exit(void) |
1099 | { |
1100 | ad5064_i2c_unregister_driver(); |
1101 | ad5064_spi_unregister_driver(); |
1102 | } |
1103 | module_exit(ad5064_exit); |
1104 | |
1105 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); |
1106 | MODULE_DESCRIPTION("Analog Devices AD5024 and similar multi-channel DACs"); |
1107 | MODULE_LICENSE("GPL v2"); |
1108 |
Definitions
- ad5064_regmap_type
- ad5064_chip_info
- ad5064_state
- ad5064_type
- ad5064_write
- ad5064_sync_powerdown_mode
- ad5064_powerdown_modes
- ltc2617_powerdown_modes
- ad5064_get_powerdown_mode
- ad5064_set_powerdown_mode
- ad5064_powerdown_mode_enum
- ltc2617_powerdown_mode_enum
- ad5064_read_dac_powerdown
- ad5064_write_dac_powerdown
- ad5064_get_vref
- ad5064_read_raw
- ad5064_write_raw
- ad5064_info
- ad5064_ext_info
- ltc2617_ext_info
- ad5024_channels
- ad5044_channels
- ad5064_channels
- ad5025_channels
- ad5045_channels
- ad5065_channels
- ad5629_channels
- ad5645_channels
- ad5669_channels
- ltc2607_channels
- ltc2617_channels
- ltc2627_channels
- ltc2631_10_channels
- ltc2631_8_channels
- ad5064_chip_info_tbl
- ad5064_num_vref
- ad5064_vref_names
- ad5064_vref_name
- ad5064_set_config
- ad5064_request_vref
- ad5064_bulk_reg_disable
- ad5064_probe
- ad5064_spi_write
- ad5064_spi_probe
- ad5064_spi_ids
- ad5064_spi_driver
- ad5064_spi_register_driver
- ad5064_spi_unregister_driver
- ad5064_i2c_write
- ad5064_i2c_probe
- ad5064_i2c_ids
- ad5064_i2c_driver
- ad5064_i2c_register_driver
- ad5064_i2c_unregister_driver
- ad5064_init
Improve your Profiling and Debugging skills
Find out more