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