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, | |
8d144c96 MA |
5 | * LTC2617, LTC2619, LTC2626, LTC2627, LTC2629 Digital to analog converters |
6 | * 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, | |
fcf265d6 LPC |
171 | }; |
172 | ||
6a17a076 | 173 | static int ad5064_write(struct ad5064_state *st, unsigned int cmd, |
fcf265d6 LPC |
174 | unsigned int addr, unsigned int val, unsigned int shift) |
175 | { | |
176 | val <<= shift; | |
177 | ||
6a17a076 | 178 | return st->write(st, cmd, addr, val); |
fcf265d6 LPC |
179 | } |
180 | ||
181 | static int ad5064_sync_powerdown_mode(struct ad5064_state *st, | |
a2630262 | 182 | const struct iio_chan_spec *chan) |
fcf265d6 | 183 | { |
78f585fe | 184 | unsigned int val, address; |
f47732c0 | 185 | unsigned int shift; |
fcf265d6 LPC |
186 | int ret; |
187 | ||
4946ff58 | 188 | if (st->chip_info->regmap_type == AD5064_REGMAP_LTC) { |
78f585fe MA |
189 | val = 0; |
190 | address = chan->address; | |
191 | } else { | |
f47732c0 LPC |
192 | if (st->chip_info->regmap_type == AD5064_REGMAP_ADI2) |
193 | shift = 4; | |
194 | else | |
195 | shift = 8; | |
196 | ||
78f585fe | 197 | val = (0x1 << chan->address); |
f47732c0 | 198 | address = 0; |
fcf265d6 | 199 | |
78f585fe | 200 | if (st->pwr_down[chan->channel]) |
f47732c0 | 201 | val |= st->pwr_down_mode[chan->channel] << shift; |
78f585fe | 202 | } |
fcf265d6 | 203 | |
78f585fe | 204 | ret = ad5064_write(st, AD5064_CMD_POWERDOWN_DAC, address, val, 0); |
fcf265d6 LPC |
205 | |
206 | return ret; | |
207 | } | |
208 | ||
26628f6b LPC |
209 | static const char * const ad5064_powerdown_modes[] = { |
210 | "1kohm_to_gnd", | |
211 | "100kohm_to_gnd", | |
212 | "three_state", | |
fcf265d6 LPC |
213 | }; |
214 | ||
8d144c96 MA |
215 | static const char * const ltc2617_powerdown_modes[] = { |
216 | "90kohm_to_gnd", | |
217 | }; | |
218 | ||
26628f6b LPC |
219 | static int ad5064_get_powerdown_mode(struct iio_dev *indio_dev, |
220 | const struct iio_chan_spec *chan) | |
fcf265d6 | 221 | { |
fcf265d6 LPC |
222 | struct ad5064_state *st = iio_priv(indio_dev); |
223 | ||
26628f6b | 224 | return st->pwr_down_mode[chan->channel] - 1; |
fcf265d6 LPC |
225 | } |
226 | ||
26628f6b LPC |
227 | static int ad5064_set_powerdown_mode(struct iio_dev *indio_dev, |
228 | const struct iio_chan_spec *chan, unsigned int mode) | |
fcf265d6 | 229 | { |
fcf265d6 | 230 | struct ad5064_state *st = iio_priv(indio_dev); |
fcf265d6 LPC |
231 | int ret; |
232 | ||
fcf265d6 | 233 | mutex_lock(&indio_dev->mlock); |
26628f6b | 234 | st->pwr_down_mode[chan->channel] = mode + 1; |
fcf265d6 | 235 | |
a2630262 | 236 | ret = ad5064_sync_powerdown_mode(st, chan); |
fcf265d6 LPC |
237 | mutex_unlock(&indio_dev->mlock); |
238 | ||
26628f6b | 239 | return ret; |
fcf265d6 LPC |
240 | } |
241 | ||
26628f6b LPC |
242 | static const struct iio_enum ad5064_powerdown_mode_enum = { |
243 | .items = ad5064_powerdown_modes, | |
244 | .num_items = ARRAY_SIZE(ad5064_powerdown_modes), | |
245 | .get = ad5064_get_powerdown_mode, | |
246 | .set = ad5064_set_powerdown_mode, | |
247 | }; | |
248 | ||
8d144c96 MA |
249 | static const struct iio_enum ltc2617_powerdown_mode_enum = { |
250 | .items = ltc2617_powerdown_modes, | |
251 | .num_items = ARRAY_SIZE(ltc2617_powerdown_modes), | |
252 | .get = ad5064_get_powerdown_mode, | |
253 | .set = ad5064_set_powerdown_mode, | |
254 | }; | |
255 | ||
1d0d8794 | 256 | static ssize_t ad5064_read_dac_powerdown(struct iio_dev *indio_dev, |
fc6d1139 | 257 | uintptr_t private, const struct iio_chan_spec *chan, char *buf) |
fcf265d6 | 258 | { |
fcf265d6 | 259 | struct ad5064_state *st = iio_priv(indio_dev); |
fcf265d6 | 260 | |
1d0d8794 | 261 | return sprintf(buf, "%d\n", st->pwr_down[chan->channel]); |
fcf265d6 LPC |
262 | } |
263 | ||
1d0d8794 | 264 | static ssize_t ad5064_write_dac_powerdown(struct iio_dev *indio_dev, |
fc6d1139 MH |
265 | uintptr_t private, const struct iio_chan_spec *chan, const char *buf, |
266 | size_t len) | |
fcf265d6 | 267 | { |
fcf265d6 | 268 | struct ad5064_state *st = iio_priv(indio_dev); |
fcf265d6 LPC |
269 | bool pwr_down; |
270 | int ret; | |
271 | ||
272 | ret = strtobool(buf, &pwr_down); | |
273 | if (ret) | |
274 | return ret; | |
275 | ||
276 | mutex_lock(&indio_dev->mlock); | |
1d0d8794 | 277 | st->pwr_down[chan->channel] = pwr_down; |
fcf265d6 | 278 | |
a2630262 | 279 | ret = ad5064_sync_powerdown_mode(st, chan); |
fcf265d6 LPC |
280 | mutex_unlock(&indio_dev->mlock); |
281 | return ret ? ret : len; | |
282 | } | |
283 | ||
bb92ff3e LPC |
284 | static int ad5064_get_vref(struct ad5064_state *st, |
285 | struct iio_chan_spec const *chan) | |
286 | { | |
287 | unsigned int i; | |
288 | ||
289 | if (st->use_internal_vref) | |
290 | return st->chip_info->internal_vref; | |
291 | ||
292 | i = st->chip_info->shared_vref ? 0 : chan->channel; | |
293 | return regulator_get_voltage(st->vref_reg[i].consumer); | |
294 | } | |
295 | ||
fcf265d6 LPC |
296 | static int ad5064_read_raw(struct iio_dev *indio_dev, |
297 | struct iio_chan_spec const *chan, | |
298 | int *val, | |
299 | int *val2, | |
300 | long m) | |
301 | { | |
302 | struct ad5064_state *st = iio_priv(indio_dev); | |
23a3b8cc | 303 | int scale_uv; |
fcf265d6 LPC |
304 | |
305 | switch (m) { | |
09f4eb40 | 306 | case IIO_CHAN_INFO_RAW: |
fcf265d6 LPC |
307 | *val = st->dac_cache[chan->channel]; |
308 | return IIO_VAL_INT; | |
c8a9f805 | 309 | case IIO_CHAN_INFO_SCALE: |
bb92ff3e | 310 | scale_uv = ad5064_get_vref(st, chan); |
fcf265d6 LPC |
311 | if (scale_uv < 0) |
312 | return scale_uv; | |
313 | ||
25682ae5 LPC |
314 | *val = scale_uv / 1000; |
315 | *val2 = chan->scan_type.realbits; | |
316 | return IIO_VAL_FRACTIONAL_LOG2; | |
fcf265d6 LPC |
317 | default: |
318 | break; | |
319 | } | |
320 | return -EINVAL; | |
321 | } | |
322 | ||
323 | static int ad5064_write_raw(struct iio_dev *indio_dev, | |
324 | struct iio_chan_spec const *chan, int val, int val2, long mask) | |
325 | { | |
326 | struct ad5064_state *st = iio_priv(indio_dev); | |
327 | int ret; | |
328 | ||
329 | switch (mask) { | |
09f4eb40 | 330 | case IIO_CHAN_INFO_RAW: |
c5ef717a | 331 | if (val >= (1 << chan->scan_type.realbits) || val < 0) |
fcf265d6 LPC |
332 | return -EINVAL; |
333 | ||
334 | mutex_lock(&indio_dev->mlock); | |
6a17a076 | 335 | ret = ad5064_write(st, AD5064_CMD_WRITE_INPUT_N_UPDATE_N, |
fcf265d6 LPC |
336 | chan->address, val, chan->scan_type.shift); |
337 | if (ret == 0) | |
338 | st->dac_cache[chan->channel] = val; | |
339 | mutex_unlock(&indio_dev->mlock); | |
340 | break; | |
341 | default: | |
342 | ret = -EINVAL; | |
343 | } | |
344 | ||
345 | return ret; | |
346 | } | |
347 | ||
348 | static const struct iio_info ad5064_info = { | |
349 | .read_raw = ad5064_read_raw, | |
350 | .write_raw = ad5064_write_raw, | |
fcf265d6 LPC |
351 | .driver_module = THIS_MODULE, |
352 | }; | |
353 | ||
26628f6b | 354 | static const struct iio_chan_spec_ext_info ad5064_ext_info[] = { |
1d0d8794 LPC |
355 | { |
356 | .name = "powerdown", | |
357 | .read = ad5064_read_dac_powerdown, | |
358 | .write = ad5064_write_dac_powerdown, | |
3704432f | 359 | .shared = IIO_SEPARATE, |
1d0d8794 | 360 | }, |
3704432f | 361 | IIO_ENUM("powerdown_mode", IIO_SEPARATE, &ad5064_powerdown_mode_enum), |
26628f6b | 362 | IIO_ENUM_AVAILABLE("powerdown_mode", &ad5064_powerdown_mode_enum), |
1d0d8794 LPC |
363 | { }, |
364 | }; | |
365 | ||
8d144c96 MA |
366 | static const struct iio_chan_spec_ext_info ltc2617_ext_info[] = { |
367 | { | |
368 | .name = "powerdown", | |
369 | .read = ad5064_read_dac_powerdown, | |
370 | .write = ad5064_write_dac_powerdown, | |
371 | .shared = IIO_SEPARATE, | |
372 | }, | |
373 | IIO_ENUM("powerdown_mode", IIO_SEPARATE, <c2617_powerdown_mode_enum), | |
374 | IIO_ENUM_AVAILABLE("powerdown_mode", <c2617_powerdown_mode_enum), | |
375 | { }, | |
376 | }; | |
377 | ||
78f585fe | 378 | #define AD5064_CHANNEL(chan, addr, bits, _shift, _ext_info) { \ |
1d0d8794 LPC |
379 | .type = IIO_VOLTAGE, \ |
380 | .indexed = 1, \ | |
381 | .output = 1, \ | |
382 | .channel = (chan), \ | |
20a0eddd JC |
383 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ |
384 | BIT(IIO_CHAN_INFO_SCALE), \ | |
a2630262 | 385 | .address = addr, \ |
81d49bc6 JC |
386 | .scan_type = { \ |
387 | .sign = 'u', \ | |
388 | .realbits = (bits), \ | |
389 | .storagebits = 16, \ | |
5dcbe97b | 390 | .shift = (_shift), \ |
81d49bc6 | 391 | }, \ |
78f585fe | 392 | .ext_info = (_ext_info), \ |
1d0d8794 LPC |
393 | } |
394 | ||
78f585fe | 395 | #define DECLARE_AD5064_CHANNELS(name, bits, shift, ext_info) \ |
83c169d5 | 396 | const struct iio_chan_spec name[] = { \ |
78f585fe MA |
397 | AD5064_CHANNEL(0, 0, bits, shift, ext_info), \ |
398 | AD5064_CHANNEL(1, 1, bits, shift, ext_info), \ | |
399 | AD5064_CHANNEL(2, 2, bits, shift, ext_info), \ | |
400 | AD5064_CHANNEL(3, 3, bits, shift, ext_info), \ | |
401 | AD5064_CHANNEL(4, 4, bits, shift, ext_info), \ | |
402 | AD5064_CHANNEL(5, 5, bits, shift, ext_info), \ | |
403 | AD5064_CHANNEL(6, 6, bits, shift, ext_info), \ | |
404 | AD5064_CHANNEL(7, 7, bits, shift, ext_info), \ | |
a2630262 LPC |
405 | } |
406 | ||
78f585fe | 407 | #define DECLARE_AD5065_CHANNELS(name, bits, shift, ext_info) \ |
a2630262 | 408 | const struct iio_chan_spec name[] = { \ |
78f585fe MA |
409 | AD5064_CHANNEL(0, 0, bits, shift, ext_info), \ |
410 | AD5064_CHANNEL(1, 3, bits, shift, ext_info), \ | |
83c169d5 LPC |
411 | } |
412 | ||
78f585fe MA |
413 | static DECLARE_AD5064_CHANNELS(ad5024_channels, 12, 8, ad5064_ext_info); |
414 | static DECLARE_AD5064_CHANNELS(ad5044_channels, 14, 6, ad5064_ext_info); | |
415 | static DECLARE_AD5064_CHANNELS(ad5064_channels, 16, 4, ad5064_ext_info); | |
83c169d5 | 416 | |
78f585fe MA |
417 | static DECLARE_AD5065_CHANNELS(ad5025_channels, 12, 8, ad5064_ext_info); |
418 | static DECLARE_AD5065_CHANNELS(ad5045_channels, 14, 6, ad5064_ext_info); | |
419 | static DECLARE_AD5065_CHANNELS(ad5065_channels, 16, 4, ad5064_ext_info); | |
5dcbe97b | 420 | |
78f585fe | 421 | static DECLARE_AD5064_CHANNELS(ad5629_channels, 12, 4, ad5064_ext_info); |
f47732c0 | 422 | static DECLARE_AD5064_CHANNELS(ad5645_channels, 14, 2, ad5064_ext_info); |
78f585fe | 423 | static DECLARE_AD5064_CHANNELS(ad5669_channels, 16, 0, ad5064_ext_info); |
a2630262 | 424 | |
8d144c96 MA |
425 | static DECLARE_AD5064_CHANNELS(ltc2607_channels, 16, 0, ltc2617_ext_info); |
426 | static DECLARE_AD5064_CHANNELS(ltc2617_channels, 14, 2, ltc2617_ext_info); | |
427 | static DECLARE_AD5064_CHANNELS(ltc2627_channels, 12, 4, ltc2617_ext_info); | |
428 | ||
1d0d8794 LPC |
429 | static const struct ad5064_chip_info ad5064_chip_info_tbl[] = { |
430 | [ID_AD5024] = { | |
431 | .shared_vref = false, | |
83c169d5 LPC |
432 | .channels = ad5024_channels, |
433 | .num_channels = 4, | |
4946ff58 | 434 | .regmap_type = AD5064_REGMAP_ADI, |
1d0d8794 | 435 | }, |
f8be4af1 LPC |
436 | [ID_AD5025] = { |
437 | .shared_vref = false, | |
a2630262 | 438 | .channels = ad5025_channels, |
f8be4af1 | 439 | .num_channels = 2, |
4946ff58 | 440 | .regmap_type = AD5064_REGMAP_ADI, |
f8be4af1 | 441 | }, |
1d0d8794 LPC |
442 | [ID_AD5044] = { |
443 | .shared_vref = false, | |
83c169d5 LPC |
444 | .channels = ad5044_channels, |
445 | .num_channels = 4, | |
4946ff58 | 446 | .regmap_type = AD5064_REGMAP_ADI, |
1d0d8794 | 447 | }, |
f8be4af1 LPC |
448 | [ID_AD5045] = { |
449 | .shared_vref = false, | |
a2630262 | 450 | .channels = ad5045_channels, |
f8be4af1 | 451 | .num_channels = 2, |
4946ff58 | 452 | .regmap_type = AD5064_REGMAP_ADI, |
f8be4af1 | 453 | }, |
1d0d8794 LPC |
454 | [ID_AD5064] = { |
455 | .shared_vref = false, | |
83c169d5 LPC |
456 | .channels = ad5064_channels, |
457 | .num_channels = 4, | |
4946ff58 | 458 | .regmap_type = AD5064_REGMAP_ADI, |
1d0d8794 LPC |
459 | }, |
460 | [ID_AD5064_1] = { | |
461 | .shared_vref = true, | |
83c169d5 LPC |
462 | .channels = ad5064_channels, |
463 | .num_channels = 4, | |
4946ff58 | 464 | .regmap_type = AD5064_REGMAP_ADI, |
1d0d8794 | 465 | }, |
f8be4af1 LPC |
466 | [ID_AD5065] = { |
467 | .shared_vref = false, | |
a2630262 | 468 | .channels = ad5065_channels, |
f8be4af1 | 469 | .num_channels = 2, |
4946ff58 | 470 | .regmap_type = AD5064_REGMAP_ADI, |
f8be4af1 | 471 | }, |
f47732c0 LPC |
472 | [ID_AD5625] = { |
473 | .shared_vref = true, | |
474 | .channels = ad5629_channels, | |
475 | .num_channels = 4, | |
476 | .regmap_type = AD5064_REGMAP_ADI2 | |
477 | }, | |
478 | [ID_AD5625R_1V25] = { | |
479 | .shared_vref = true, | |
480 | .internal_vref = 1250000, | |
481 | .channels = ad5629_channels, | |
482 | .num_channels = 4, | |
483 | .regmap_type = AD5064_REGMAP_ADI2 | |
484 | }, | |
485 | [ID_AD5625R_2V5] = { | |
486 | .shared_vref = true, | |
487 | .internal_vref = 2500000, | |
488 | .channels = ad5629_channels, | |
489 | .num_channels = 4, | |
490 | .regmap_type = AD5064_REGMAP_ADI2 | |
491 | }, | |
492 | [ID_AD5627] = { | |
493 | .shared_vref = true, | |
494 | .channels = ad5629_channels, | |
495 | .num_channels = 2, | |
496 | .regmap_type = AD5064_REGMAP_ADI2 | |
497 | }, | |
498 | [ID_AD5627R_1V25] = { | |
499 | .shared_vref = true, | |
500 | .internal_vref = 1250000, | |
501 | .channels = ad5629_channels, | |
502 | .num_channels = 2, | |
503 | .regmap_type = AD5064_REGMAP_ADI2 | |
504 | }, | |
505 | [ID_AD5627R_2V5] = { | |
506 | .shared_vref = true, | |
507 | .internal_vref = 2500000, | |
508 | .channels = ad5629_channels, | |
509 | .num_channels = 2, | |
510 | .regmap_type = AD5064_REGMAP_ADI2 | |
511 | }, | |
bb92ff3e LPC |
512 | [ID_AD5628_1] = { |
513 | .shared_vref = true, | |
514 | .internal_vref = 2500000, | |
515 | .channels = ad5024_channels, | |
516 | .num_channels = 8, | |
4946ff58 | 517 | .regmap_type = AD5064_REGMAP_ADI, |
bb92ff3e LPC |
518 | }, |
519 | [ID_AD5628_2] = { | |
520 | .shared_vref = true, | |
521 | .internal_vref = 5000000, | |
522 | .channels = ad5024_channels, | |
523 | .num_channels = 8, | |
4946ff58 | 524 | .regmap_type = AD5064_REGMAP_ADI, |
bb92ff3e | 525 | }, |
5dcbe97b LPC |
526 | [ID_AD5629_1] = { |
527 | .shared_vref = true, | |
528 | .internal_vref = 2500000, | |
529 | .channels = ad5629_channels, | |
530 | .num_channels = 8, | |
4946ff58 | 531 | .regmap_type = AD5064_REGMAP_ADI, |
5dcbe97b LPC |
532 | }, |
533 | [ID_AD5629_2] = { | |
534 | .shared_vref = true, | |
535 | .internal_vref = 5000000, | |
536 | .channels = ad5629_channels, | |
537 | .num_channels = 8, | |
4946ff58 | 538 | .regmap_type = AD5064_REGMAP_ADI, |
5dcbe97b | 539 | }, |
f47732c0 LPC |
540 | [ID_AD5645R_1V25] = { |
541 | .shared_vref = true, | |
542 | .internal_vref = 1250000, | |
543 | .channels = ad5645_channels, | |
544 | .num_channels = 4, | |
545 | .regmap_type = AD5064_REGMAP_ADI2 | |
546 | }, | |
547 | [ID_AD5645R_2V5] = { | |
548 | .shared_vref = true, | |
549 | .internal_vref = 2500000, | |
550 | .channels = ad5645_channels, | |
551 | .num_channels = 4, | |
552 | .regmap_type = AD5064_REGMAP_ADI2 | |
553 | }, | |
554 | [ID_AD5647R_1V25] = { | |
555 | .shared_vref = true, | |
556 | .internal_vref = 1250000, | |
557 | .channels = ad5645_channels, | |
558 | .num_channels = 2, | |
559 | .regmap_type = AD5064_REGMAP_ADI2 | |
560 | }, | |
561 | [ID_AD5647R_2V5] = { | |
562 | .shared_vref = true, | |
563 | .internal_vref = 2500000, | |
564 | .channels = ad5645_channels, | |
565 | .num_channels = 2, | |
566 | .regmap_type = AD5064_REGMAP_ADI2 | |
567 | }, | |
bb92ff3e LPC |
568 | [ID_AD5648_1] = { |
569 | .shared_vref = true, | |
570 | .internal_vref = 2500000, | |
571 | .channels = ad5044_channels, | |
572 | .num_channels = 8, | |
4946ff58 | 573 | .regmap_type = AD5064_REGMAP_ADI, |
bb92ff3e LPC |
574 | }, |
575 | [ID_AD5648_2] = { | |
576 | .shared_vref = true, | |
577 | .internal_vref = 5000000, | |
578 | .channels = ad5044_channels, | |
579 | .num_channels = 8, | |
4946ff58 | 580 | .regmap_type = AD5064_REGMAP_ADI, |
bb92ff3e | 581 | }, |
f47732c0 LPC |
582 | [ID_AD5665] = { |
583 | .shared_vref = true, | |
584 | .channels = ad5669_channels, | |
585 | .num_channels = 4, | |
586 | .regmap_type = AD5064_REGMAP_ADI2 | |
587 | }, | |
588 | [ID_AD5665R_1V25] = { | |
589 | .shared_vref = true, | |
590 | .internal_vref = 1250000, | |
591 | .channels = ad5669_channels, | |
592 | .num_channels = 4, | |
593 | .regmap_type = AD5064_REGMAP_ADI2 | |
594 | }, | |
595 | [ID_AD5665R_2V5] = { | |
596 | .shared_vref = true, | |
597 | .internal_vref = 2500000, | |
598 | .channels = ad5669_channels, | |
599 | .num_channels = 4, | |
600 | .regmap_type = AD5064_REGMAP_ADI2 | |
601 | }, | |
64f4eaa5 LPC |
602 | [ID_AD5666_1] = { |
603 | .shared_vref = true, | |
604 | .internal_vref = 2500000, | |
605 | .channels = ad5064_channels, | |
606 | .num_channels = 4, | |
4946ff58 | 607 | .regmap_type = AD5064_REGMAP_ADI, |
64f4eaa5 LPC |
608 | }, |
609 | [ID_AD5666_2] = { | |
610 | .shared_vref = true, | |
611 | .internal_vref = 5000000, | |
612 | .channels = ad5064_channels, | |
613 | .num_channels = 4, | |
4946ff58 | 614 | .regmap_type = AD5064_REGMAP_ADI, |
64f4eaa5 | 615 | }, |
f47732c0 LPC |
616 | [ID_AD5667] = { |
617 | .shared_vref = true, | |
618 | .channels = ad5669_channels, | |
619 | .num_channels = 2, | |
620 | .regmap_type = AD5064_REGMAP_ADI2 | |
621 | }, | |
622 | [ID_AD5667R_1V25] = { | |
623 | .shared_vref = true, | |
624 | .internal_vref = 1250000, | |
625 | .channels = ad5669_channels, | |
626 | .num_channels = 2, | |
627 | .regmap_type = AD5064_REGMAP_ADI2 | |
628 | }, | |
629 | [ID_AD5667R_2V5] = { | |
630 | .shared_vref = true, | |
631 | .internal_vref = 2500000, | |
632 | .channels = ad5669_channels, | |
633 | .num_channels = 2, | |
634 | .regmap_type = AD5064_REGMAP_ADI2 | |
635 | }, | |
bb92ff3e LPC |
636 | [ID_AD5668_1] = { |
637 | .shared_vref = true, | |
638 | .internal_vref = 2500000, | |
639 | .channels = ad5064_channels, | |
640 | .num_channels = 8, | |
4946ff58 | 641 | .regmap_type = AD5064_REGMAP_ADI, |
bb92ff3e LPC |
642 | }, |
643 | [ID_AD5668_2] = { | |
644 | .shared_vref = true, | |
645 | .internal_vref = 5000000, | |
646 | .channels = ad5064_channels, | |
647 | .num_channels = 8, | |
4946ff58 | 648 | .regmap_type = AD5064_REGMAP_ADI, |
bb92ff3e | 649 | }, |
5dcbe97b LPC |
650 | [ID_AD5669_1] = { |
651 | .shared_vref = true, | |
652 | .internal_vref = 2500000, | |
653 | .channels = ad5669_channels, | |
654 | .num_channels = 8, | |
4946ff58 | 655 | .regmap_type = AD5064_REGMAP_ADI, |
5dcbe97b LPC |
656 | }, |
657 | [ID_AD5669_2] = { | |
658 | .shared_vref = true, | |
659 | .internal_vref = 5000000, | |
660 | .channels = ad5669_channels, | |
661 | .num_channels = 8, | |
4946ff58 | 662 | .regmap_type = AD5064_REGMAP_ADI, |
5dcbe97b | 663 | }, |
8d144c96 MA |
664 | [ID_LTC2606] = { |
665 | .shared_vref = true, | |
666 | .internal_vref = 0, | |
667 | .channels = ltc2607_channels, | |
668 | .num_channels = 1, | |
4946ff58 | 669 | .regmap_type = AD5064_REGMAP_LTC, |
8d144c96 MA |
670 | }, |
671 | [ID_LTC2607] = { | |
672 | .shared_vref = true, | |
673 | .internal_vref = 0, | |
674 | .channels = ltc2607_channels, | |
675 | .num_channels = 2, | |
4946ff58 | 676 | .regmap_type = AD5064_REGMAP_LTC, |
8d144c96 MA |
677 | }, |
678 | [ID_LTC2609] = { | |
679 | .shared_vref = false, | |
680 | .internal_vref = 0, | |
681 | .channels = ltc2607_channels, | |
682 | .num_channels = 4, | |
4946ff58 | 683 | .regmap_type = AD5064_REGMAP_LTC, |
8d144c96 MA |
684 | }, |
685 | [ID_LTC2616] = { | |
686 | .shared_vref = true, | |
687 | .internal_vref = 0, | |
688 | .channels = ltc2617_channels, | |
689 | .num_channels = 1, | |
4946ff58 | 690 | .regmap_type = AD5064_REGMAP_LTC, |
8d144c96 MA |
691 | }, |
692 | [ID_LTC2617] = { | |
693 | .shared_vref = true, | |
694 | .internal_vref = 0, | |
695 | .channels = ltc2617_channels, | |
696 | .num_channels = 2, | |
4946ff58 | 697 | .regmap_type = AD5064_REGMAP_LTC, |
8d144c96 MA |
698 | }, |
699 | [ID_LTC2619] = { | |
700 | .shared_vref = false, | |
701 | .internal_vref = 0, | |
702 | .channels = ltc2617_channels, | |
703 | .num_channels = 4, | |
4946ff58 | 704 | .regmap_type = AD5064_REGMAP_LTC, |
8d144c96 MA |
705 | }, |
706 | [ID_LTC2626] = { | |
707 | .shared_vref = true, | |
708 | .internal_vref = 0, | |
709 | .channels = ltc2627_channels, | |
710 | .num_channels = 1, | |
4946ff58 | 711 | .regmap_type = AD5064_REGMAP_LTC, |
8d144c96 MA |
712 | }, |
713 | [ID_LTC2627] = { | |
714 | .shared_vref = true, | |
715 | .internal_vref = 0, | |
716 | .channels = ltc2627_channels, | |
717 | .num_channels = 2, | |
4946ff58 | 718 | .regmap_type = AD5064_REGMAP_LTC, |
8d144c96 MA |
719 | }, |
720 | [ID_LTC2629] = { | |
721 | .shared_vref = false, | |
722 | .internal_vref = 0, | |
723 | .channels = ltc2627_channels, | |
724 | .num_channels = 4, | |
4946ff58 | 725 | .regmap_type = AD5064_REGMAP_LTC, |
8d144c96 | 726 | }, |
1d0d8794 LPC |
727 | }; |
728 | ||
fcf265d6 LPC |
729 | static inline unsigned int ad5064_num_vref(struct ad5064_state *st) |
730 | { | |
83c169d5 | 731 | return st->chip_info->shared_vref ? 1 : st->chip_info->num_channels; |
fcf265d6 LPC |
732 | } |
733 | ||
734 | static const char * const ad5064_vref_names[] = { | |
735 | "vrefA", | |
736 | "vrefB", | |
737 | "vrefC", | |
738 | "vrefD", | |
739 | }; | |
740 | ||
741 | static const char * const ad5064_vref_name(struct ad5064_state *st, | |
742 | unsigned int vref) | |
743 | { | |
744 | return st->chip_info->shared_vref ? "vref" : ad5064_vref_names[vref]; | |
745 | } | |
746 | ||
f47732c0 LPC |
747 | static int ad5064_set_config(struct ad5064_state *st, unsigned int val) |
748 | { | |
749 | unsigned int cmd; | |
750 | ||
751 | switch (st->chip_info->regmap_type) { | |
752 | case AD5064_REGMAP_ADI2: | |
753 | cmd = AD5064_CMD_CONFIG_V2; | |
754 | break; | |
755 | default: | |
756 | cmd = AD5064_CMD_CONFIG; | |
757 | break; | |
758 | } | |
759 | ||
760 | return ad5064_write(st, cmd, 0, val, 0); | |
761 | } | |
762 | ||
fc52692c GKH |
763 | static int ad5064_probe(struct device *dev, enum ad5064_type type, |
764 | const char *name, ad5064_write_func write) | |
fcf265d6 | 765 | { |
fcf265d6 LPC |
766 | struct iio_dev *indio_dev; |
767 | struct ad5064_state *st; | |
f77ae9d8 | 768 | unsigned int midscale; |
fcf265d6 LPC |
769 | unsigned int i; |
770 | int ret; | |
771 | ||
c367982a | 772 | indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); |
fcf265d6 LPC |
773 | if (indio_dev == NULL) |
774 | return -ENOMEM; | |
775 | ||
776 | st = iio_priv(indio_dev); | |
6a17a076 | 777 | dev_set_drvdata(dev, indio_dev); |
fcf265d6 LPC |
778 | |
779 | st->chip_info = &ad5064_chip_info_tbl[type]; | |
6a17a076 LPC |
780 | st->dev = dev; |
781 | st->write = write; | |
fcf265d6 LPC |
782 | |
783 | for (i = 0; i < ad5064_num_vref(st); ++i) | |
784 | st->vref_reg[i].supply = ad5064_vref_name(st, i); | |
785 | ||
c367982a | 786 | ret = devm_regulator_bulk_get(dev, ad5064_num_vref(st), |
fcf265d6 | 787 | st->vref_reg); |
bb92ff3e LPC |
788 | if (ret) { |
789 | if (!st->chip_info->internal_vref) | |
c367982a | 790 | return ret; |
bb92ff3e | 791 | st->use_internal_vref = true; |
f47732c0 | 792 | ret = ad5064_set_config(st, AD5064_CONFIG_INT_VREF_ENABLE); |
bb92ff3e | 793 | if (ret) { |
6a17a076 | 794 | dev_err(dev, "Failed to enable internal vref: %d\n", |
bb92ff3e | 795 | ret); |
c367982a | 796 | return ret; |
bb92ff3e LPC |
797 | } |
798 | } else { | |
799 | ret = regulator_bulk_enable(ad5064_num_vref(st), st->vref_reg); | |
800 | if (ret) | |
c367982a | 801 | return ret; |
bb92ff3e | 802 | } |
fcf265d6 | 803 | |
6a17a076 LPC |
804 | indio_dev->dev.parent = dev; |
805 | indio_dev->name = name; | |
fcf265d6 LPC |
806 | indio_dev->info = &ad5064_info; |
807 | indio_dev->modes = INDIO_DIRECT_MODE; | |
83c169d5 LPC |
808 | indio_dev->channels = st->chip_info->channels; |
809 | indio_dev->num_channels = st->chip_info->num_channels; | |
fcf265d6 | 810 | |
f77ae9d8 LPC |
811 | midscale = (1 << indio_dev->channels[0].scan_type.realbits) / 2; |
812 | ||
813 | for (i = 0; i < st->chip_info->num_channels; ++i) { | |
814 | st->pwr_down_mode[i] = AD5064_LDAC_PWRDN_1K; | |
815 | st->dac_cache[i] = midscale; | |
816 | } | |
817 | ||
fcf265d6 LPC |
818 | ret = iio_device_register(indio_dev); |
819 | if (ret) | |
820 | goto error_disable_reg; | |
821 | ||
822 | return 0; | |
823 | ||
824 | error_disable_reg: | |
bb92ff3e LPC |
825 | if (!st->use_internal_vref) |
826 | regulator_bulk_disable(ad5064_num_vref(st), st->vref_reg); | |
fcf265d6 LPC |
827 | |
828 | return ret; | |
829 | } | |
830 | ||
fc52692c | 831 | static int ad5064_remove(struct device *dev) |
fcf265d6 | 832 | { |
6a17a076 | 833 | struct iio_dev *indio_dev = dev_get_drvdata(dev); |
fcf265d6 LPC |
834 | struct ad5064_state *st = iio_priv(indio_dev); |
835 | ||
836 | iio_device_unregister(indio_dev); | |
837 | ||
c367982a | 838 | if (!st->use_internal_vref) |
bb92ff3e | 839 | regulator_bulk_disable(ad5064_num_vref(st), st->vref_reg); |
fcf265d6 LPC |
840 | |
841 | return 0; | |
842 | } | |
843 | ||
6a17a076 LPC |
844 | #if IS_ENABLED(CONFIG_SPI_MASTER) |
845 | ||
9660ac70 LPC |
846 | static int ad5064_spi_write(struct ad5064_state *st, unsigned int cmd, |
847 | unsigned int addr, unsigned int val) | |
848 | { | |
849 | struct spi_device *spi = to_spi_device(st->dev); | |
850 | ||
851 | st->data.spi = cpu_to_be32(AD5064_CMD(cmd) | AD5064_ADDR(addr) | val); | |
852 | return spi_write(spi, &st->data.spi, sizeof(st->data.spi)); | |
853 | } | |
854 | ||
fc52692c | 855 | static int ad5064_spi_probe(struct spi_device *spi) |
6a17a076 LPC |
856 | { |
857 | const struct spi_device_id *id = spi_get_device_id(spi); | |
858 | ||
859 | return ad5064_probe(&spi->dev, id->driver_data, id->name, | |
860 | ad5064_spi_write); | |
861 | } | |
862 | ||
fc52692c | 863 | static int ad5064_spi_remove(struct spi_device *spi) |
6a17a076 LPC |
864 | { |
865 | return ad5064_remove(&spi->dev); | |
866 | } | |
867 | ||
868 | static const struct spi_device_id ad5064_spi_ids[] = { | |
fcf265d6 | 869 | {"ad5024", ID_AD5024}, |
f8be4af1 | 870 | {"ad5025", ID_AD5025}, |
fcf265d6 | 871 | {"ad5044", ID_AD5044}, |
f8be4af1 | 872 | {"ad5045", ID_AD5045}, |
fcf265d6 LPC |
873 | {"ad5064", ID_AD5064}, |
874 | {"ad5064-1", ID_AD5064_1}, | |
f8be4af1 | 875 | {"ad5065", ID_AD5065}, |
bb92ff3e LPC |
876 | {"ad5628-1", ID_AD5628_1}, |
877 | {"ad5628-2", ID_AD5628_2}, | |
878 | {"ad5648-1", ID_AD5648_1}, | |
879 | {"ad5648-2", ID_AD5648_2}, | |
64f4eaa5 LPC |
880 | {"ad5666-1", ID_AD5666_1}, |
881 | {"ad5666-2", ID_AD5666_2}, | |
bb92ff3e LPC |
882 | {"ad5668-1", ID_AD5668_1}, |
883 | {"ad5668-2", ID_AD5668_2}, | |
884 | {"ad5668-3", ID_AD5668_2}, /* similar enough to ad5668-2 */ | |
fcf265d6 LPC |
885 | {} |
886 | }; | |
6a17a076 | 887 | MODULE_DEVICE_TABLE(spi, ad5064_spi_ids); |
fcf265d6 | 888 | |
6a17a076 | 889 | static struct spi_driver ad5064_spi_driver = { |
fcf265d6 LPC |
890 | .driver = { |
891 | .name = "ad5064", | |
fcf265d6 | 892 | }, |
6a17a076 | 893 | .probe = ad5064_spi_probe, |
fc52692c | 894 | .remove = ad5064_spi_remove, |
6a17a076 | 895 | .id_table = ad5064_spi_ids, |
fcf265d6 | 896 | }; |
6a17a076 LPC |
897 | |
898 | static int __init ad5064_spi_register_driver(void) | |
899 | { | |
900 | return spi_register_driver(&ad5064_spi_driver); | |
901 | } | |
902 | ||
21fa54e4 | 903 | static void ad5064_spi_unregister_driver(void) |
6a17a076 LPC |
904 | { |
905 | spi_unregister_driver(&ad5064_spi_driver); | |
906 | } | |
907 | ||
908 | #else | |
909 | ||
910 | static inline int ad5064_spi_register_driver(void) { return 0; } | |
911 | static inline void ad5064_spi_unregister_driver(void) { } | |
912 | ||
913 | #endif | |
914 | ||
915 | #if IS_ENABLED(CONFIG_I2C) | |
916 | ||
9660ac70 LPC |
917 | static int ad5064_i2c_write(struct ad5064_state *st, unsigned int cmd, |
918 | unsigned int addr, unsigned int val) | |
919 | { | |
920 | struct i2c_client *i2c = to_i2c_client(st->dev); | |
f47732c0 | 921 | unsigned int cmd_shift; |
03fe472e | 922 | int ret; |
9660ac70 | 923 | |
f47732c0 LPC |
924 | switch (st->chip_info->regmap_type) { |
925 | case AD5064_REGMAP_ADI2: | |
926 | cmd_shift = 3; | |
927 | break; | |
928 | default: | |
929 | cmd_shift = 4; | |
930 | break; | |
931 | } | |
932 | ||
933 | st->data.i2c[0] = (cmd << cmd_shift) | addr; | |
9660ac70 | 934 | put_unaligned_be16(val, &st->data.i2c[1]); |
03fe472e MH |
935 | |
936 | ret = i2c_master_send(i2c, st->data.i2c, 3); | |
937 | if (ret < 0) | |
938 | return ret; | |
939 | ||
940 | return 0; | |
9660ac70 LPC |
941 | } |
942 | ||
fc52692c | 943 | static int ad5064_i2c_probe(struct i2c_client *i2c, |
6a17a076 LPC |
944 | const struct i2c_device_id *id) |
945 | { | |
946 | return ad5064_probe(&i2c->dev, id->driver_data, id->name, | |
947 | ad5064_i2c_write); | |
948 | } | |
949 | ||
fc52692c | 950 | static int ad5064_i2c_remove(struct i2c_client *i2c) |
6a17a076 LPC |
951 | { |
952 | return ad5064_remove(&i2c->dev); | |
953 | } | |
954 | ||
955 | static const struct i2c_device_id ad5064_i2c_ids[] = { | |
f47732c0 LPC |
956 | {"ad5625", ID_AD5625 }, |
957 | {"ad5625r-1v25", ID_AD5625R_1V25 }, | |
958 | {"ad5625r-2v5", ID_AD5625R_2V5 }, | |
959 | {"ad5627", ID_AD5627 }, | |
960 | {"ad5627r-1v25", ID_AD5627R_1V25 }, | |
961 | {"ad5627r-2v5", ID_AD5627R_2V5 }, | |
5dcbe97b LPC |
962 | {"ad5629-1", ID_AD5629_1}, |
963 | {"ad5629-2", ID_AD5629_2}, | |
964 | {"ad5629-3", ID_AD5629_2}, /* similar enough to ad5629-2 */ | |
f47732c0 LPC |
965 | {"ad5645r-1v25", ID_AD5645R_1V25 }, |
966 | {"ad5645r-2v5", ID_AD5645R_2V5 }, | |
967 | {"ad5665", ID_AD5665 }, | |
968 | {"ad5665r-1v25", ID_AD5665R_1V25 }, | |
969 | {"ad5665r-2v5", ID_AD5665R_2V5 }, | |
970 | {"ad5667", ID_AD5667 }, | |
971 | {"ad5667r-1v25", ID_AD5667R_1V25 }, | |
972 | {"ad5667r-2v5", ID_AD5667R_2V5 }, | |
5dcbe97b LPC |
973 | {"ad5669-1", ID_AD5669_1}, |
974 | {"ad5669-2", ID_AD5669_2}, | |
975 | {"ad5669-3", ID_AD5669_2}, /* similar enough to ad5669-2 */ | |
8d144c96 MA |
976 | {"ltc2606", ID_LTC2606}, |
977 | {"ltc2607", ID_LTC2607}, | |
978 | {"ltc2609", ID_LTC2609}, | |
979 | {"ltc2616", ID_LTC2616}, | |
980 | {"ltc2617", ID_LTC2617}, | |
981 | {"ltc2619", ID_LTC2619}, | |
982 | {"ltc2626", ID_LTC2626}, | |
983 | {"ltc2627", ID_LTC2627}, | |
984 | {"ltc2629", ID_LTC2629}, | |
6a17a076 LPC |
985 | {} |
986 | }; | |
987 | MODULE_DEVICE_TABLE(i2c, ad5064_i2c_ids); | |
988 | ||
989 | static struct i2c_driver ad5064_i2c_driver = { | |
990 | .driver = { | |
991 | .name = "ad5064", | |
6a17a076 LPC |
992 | }, |
993 | .probe = ad5064_i2c_probe, | |
fc52692c | 994 | .remove = ad5064_i2c_remove, |
6a17a076 LPC |
995 | .id_table = ad5064_i2c_ids, |
996 | }; | |
997 | ||
998 | static int __init ad5064_i2c_register_driver(void) | |
999 | { | |
1000 | return i2c_add_driver(&ad5064_i2c_driver); | |
1001 | } | |
1002 | ||
1003 | static void __exit ad5064_i2c_unregister_driver(void) | |
1004 | { | |
1005 | i2c_del_driver(&ad5064_i2c_driver); | |
1006 | } | |
1007 | ||
1008 | #else | |
1009 | ||
1010 | static inline int ad5064_i2c_register_driver(void) { return 0; } | |
1011 | static inline void ad5064_i2c_unregister_driver(void) { } | |
1012 | ||
1013 | #endif | |
1014 | ||
1015 | static int __init ad5064_init(void) | |
1016 | { | |
1017 | int ret; | |
1018 | ||
1019 | ret = ad5064_spi_register_driver(); | |
1020 | if (ret) | |
1021 | return ret; | |
1022 | ||
1023 | ret = ad5064_i2c_register_driver(); | |
1024 | if (ret) { | |
1025 | ad5064_spi_unregister_driver(); | |
1026 | return ret; | |
1027 | } | |
1028 | ||
1029 | return 0; | |
1030 | } | |
1031 | module_init(ad5064_init); | |
1032 | ||
1033 | static void __exit ad5064_exit(void) | |
1034 | { | |
1035 | ad5064_i2c_unregister_driver(); | |
1036 | ad5064_spi_unregister_driver(); | |
1037 | } | |
1038 | module_exit(ad5064_exit); | |
fcf265d6 LPC |
1039 | |
1040 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); | |
6a17a076 | 1041 | MODULE_DESCRIPTION("Analog Devices AD5024 and similar multi-channel DACs"); |
fcf265d6 | 1042 | MODULE_LICENSE("GPL v2"); |