diff options
Diffstat (limited to 'drivers/iio/dac/ad5380.c')
-rw-r--r-- | drivers/iio/dac/ad5380.c | 657 |
1 files changed, 657 insertions, 0 deletions
diff --git a/drivers/iio/dac/ad5380.c b/drivers/iio/dac/ad5380.c new file mode 100644 index 000000000000..5dfb4451728f --- /dev/null +++ b/drivers/iio/dac/ad5380.c | |||
@@ -0,0 +1,657 @@ | |||
1 | /* | ||
2 | * Analog devices AD5380, AD5381, AD5382, AD5383, AD5390, AD5391, AD5392 | ||
3 | * multi-channel Digital to Analog Converters driver | ||
4 | * | ||
5 | * Copyright 2011 Analog Devices Inc. | ||
6 | * | ||
7 | * Licensed under the GPL-2. | ||
8 | */ | ||
9 | |||
10 | #include <linux/device.h> | ||
11 | #include <linux/err.h> | ||
12 | #include <linux/i2c.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/spi/spi.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include <linux/sysfs.h> | ||
18 | #include <linux/regmap.h> | ||
19 | #include <linux/regulator/consumer.h> | ||
20 | |||
21 | #include <linux/iio/iio.h> | ||
22 | #include <linux/iio/sysfs.h> | ||
23 | |||
24 | #define AD5380_REG_DATA(x) (((x) << 2) | 3) | ||
25 | #define AD5380_REG_OFFSET(x) (((x) << 2) | 2) | ||
26 | #define AD5380_REG_GAIN(x) (((x) << 2) | 1) | ||
27 | #define AD5380_REG_SF_PWR_DOWN (8 << 2) | ||
28 | #define AD5380_REG_SF_PWR_UP (9 << 2) | ||
29 | #define AD5380_REG_SF_CTRL (12 << 2) | ||
30 | |||
31 | #define AD5380_CTRL_PWR_DOWN_MODE_OFFSET 13 | ||
32 | #define AD5380_CTRL_INT_VREF_2V5 BIT(12) | ||
33 | #define AD5380_CTRL_INT_VREF_EN BIT(10) | ||
34 | |||
35 | /** | ||
36 | * struct ad5380_chip_info - chip specific information | ||
37 | * @channel_template: channel specification template | ||
38 | * @num_channels: number of channels | ||
39 | * @int_vref: internal vref in uV | ||
40 | */ | ||
41 | |||
42 | struct ad5380_chip_info { | ||
43 | struct iio_chan_spec channel_template; | ||
44 | unsigned int num_channels; | ||
45 | unsigned int int_vref; | ||
46 | }; | ||
47 | |||
48 | /** | ||
49 | * struct ad5380_state - driver instance specific data | ||
50 | * @regmap: regmap instance used by the device | ||
51 | * @chip_info: chip model specific constants, available modes etc | ||
52 | * @vref_reg: vref supply regulator | ||
53 | * @vref: actual reference voltage used in uA | ||
54 | * @pwr_down: whether the chip is currently in power down mode | ||
55 | */ | ||
56 | |||
57 | struct ad5380_state { | ||
58 | struct regmap *regmap; | ||
59 | const struct ad5380_chip_info *chip_info; | ||
60 | struct regulator *vref_reg; | ||
61 | int vref; | ||
62 | bool pwr_down; | ||
63 | }; | ||
64 | |||
65 | enum ad5380_type { | ||
66 | ID_AD5380_3, | ||
67 | ID_AD5380_5, | ||
68 | ID_AD5381_3, | ||
69 | ID_AD5381_5, | ||
70 | ID_AD5382_3, | ||
71 | ID_AD5382_5, | ||
72 | ID_AD5383_3, | ||
73 | ID_AD5383_5, | ||
74 | ID_AD5390_3, | ||
75 | ID_AD5390_5, | ||
76 | ID_AD5391_3, | ||
77 | ID_AD5391_5, | ||
78 | ID_AD5392_3, | ||
79 | ID_AD5392_5, | ||
80 | }; | ||
81 | |||
82 | static ssize_t ad5380_read_dac_powerdown(struct iio_dev *indio_dev, | ||
83 | uintptr_t private, const struct iio_chan_spec *chan, char *buf) | ||
84 | { | ||
85 | struct ad5380_state *st = iio_priv(indio_dev); | ||
86 | |||
87 | return sprintf(buf, "%d\n", st->pwr_down); | ||
88 | } | ||
89 | |||
90 | static ssize_t ad5380_write_dac_powerdown(struct iio_dev *indio_dev, | ||
91 | uintptr_t private, const struct iio_chan_spec *chan, const char *buf, | ||
92 | size_t len) | ||
93 | { | ||
94 | struct ad5380_state *st = iio_priv(indio_dev); | ||
95 | bool pwr_down; | ||
96 | int ret; | ||
97 | |||
98 | ret = strtobool(buf, &pwr_down); | ||
99 | if (ret) | ||
100 | return ret; | ||
101 | |||
102 | mutex_lock(&indio_dev->mlock); | ||
103 | |||
104 | if (pwr_down) | ||
105 | ret = regmap_write(st->regmap, AD5380_REG_SF_PWR_DOWN, 0); | ||
106 | else | ||
107 | ret = regmap_write(st->regmap, AD5380_REG_SF_PWR_UP, 0); | ||
108 | |||
109 | st->pwr_down = pwr_down; | ||
110 | |||
111 | mutex_unlock(&indio_dev->mlock); | ||
112 | |||
113 | return ret ? ret : len; | ||
114 | } | ||
115 | |||
116 | static const char * const ad5380_powerdown_modes[] = { | ||
117 | "100kohm_to_gnd", | ||
118 | "three_state", | ||
119 | }; | ||
120 | |||
121 | static int ad5380_get_powerdown_mode(struct iio_dev *indio_dev, | ||
122 | const struct iio_chan_spec *chan) | ||
123 | { | ||
124 | struct ad5380_state *st = iio_priv(indio_dev); | ||
125 | unsigned int mode; | ||
126 | int ret; | ||
127 | |||
128 | ret = regmap_read(st->regmap, AD5380_REG_SF_CTRL, &mode); | ||
129 | if (ret) | ||
130 | return ret; | ||
131 | |||
132 | mode = (mode >> AD5380_CTRL_PWR_DOWN_MODE_OFFSET) & 1; | ||
133 | |||
134 | return mode; | ||
135 | } | ||
136 | |||
137 | static int ad5380_set_powerdown_mode(struct iio_dev *indio_dev, | ||
138 | const struct iio_chan_spec *chan, unsigned int mode) | ||
139 | { | ||
140 | struct ad5380_state *st = iio_priv(indio_dev); | ||
141 | int ret; | ||
142 | |||
143 | ret = regmap_update_bits(st->regmap, AD5380_REG_SF_CTRL, | ||
144 | 1 << AD5380_CTRL_PWR_DOWN_MODE_OFFSET, | ||
145 | mode << AD5380_CTRL_PWR_DOWN_MODE_OFFSET); | ||
146 | |||
147 | return ret; | ||
148 | } | ||
149 | |||
150 | static const struct iio_enum ad5380_powerdown_mode_enum = { | ||
151 | .items = ad5380_powerdown_modes, | ||
152 | .num_items = ARRAY_SIZE(ad5380_powerdown_modes), | ||
153 | .get = ad5380_get_powerdown_mode, | ||
154 | .set = ad5380_set_powerdown_mode, | ||
155 | }; | ||
156 | |||
157 | static unsigned int ad5380_info_to_reg(struct iio_chan_spec const *chan, | ||
158 | long info) | ||
159 | { | ||
160 | switch (info) { | ||
161 | case 0: | ||
162 | return AD5380_REG_DATA(chan->address); | ||
163 | case IIO_CHAN_INFO_CALIBBIAS: | ||
164 | return AD5380_REG_OFFSET(chan->address); | ||
165 | case IIO_CHAN_INFO_CALIBSCALE: | ||
166 | return AD5380_REG_GAIN(chan->address); | ||
167 | default: | ||
168 | break; | ||
169 | } | ||
170 | |||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | static int ad5380_write_raw(struct iio_dev *indio_dev, | ||
175 | struct iio_chan_spec const *chan, int val, int val2, long info) | ||
176 | { | ||
177 | const unsigned int max_val = (1 << chan->scan_type.realbits); | ||
178 | struct ad5380_state *st = iio_priv(indio_dev); | ||
179 | |||
180 | switch (info) { | ||
181 | case IIO_CHAN_INFO_RAW: | ||
182 | case IIO_CHAN_INFO_CALIBSCALE: | ||
183 | if (val >= max_val || val < 0) | ||
184 | return -EINVAL; | ||
185 | |||
186 | return regmap_write(st->regmap, | ||
187 | ad5380_info_to_reg(chan, info), | ||
188 | val << chan->scan_type.shift); | ||
189 | case IIO_CHAN_INFO_CALIBBIAS: | ||
190 | val += (1 << chan->scan_type.realbits) / 2; | ||
191 | if (val >= max_val || val < 0) | ||
192 | return -EINVAL; | ||
193 | |||
194 | return regmap_write(st->regmap, | ||
195 | AD5380_REG_OFFSET(chan->address), | ||
196 | val << chan->scan_type.shift); | ||
197 | default: | ||
198 | break; | ||
199 | } | ||
200 | return -EINVAL; | ||
201 | } | ||
202 | |||
203 | static int ad5380_read_raw(struct iio_dev *indio_dev, | ||
204 | struct iio_chan_spec const *chan, int *val, int *val2, long info) | ||
205 | { | ||
206 | struct ad5380_state *st = iio_priv(indio_dev); | ||
207 | unsigned long scale_uv; | ||
208 | int ret; | ||
209 | |||
210 | switch (info) { | ||
211 | case IIO_CHAN_INFO_RAW: | ||
212 | case IIO_CHAN_INFO_CALIBSCALE: | ||
213 | ret = regmap_read(st->regmap, ad5380_info_to_reg(chan, info), | ||
214 | val); | ||
215 | if (ret) | ||
216 | return ret; | ||
217 | *val >>= chan->scan_type.shift; | ||
218 | return IIO_VAL_INT; | ||
219 | case IIO_CHAN_INFO_CALIBBIAS: | ||
220 | ret = regmap_read(st->regmap, AD5380_REG_OFFSET(chan->address), | ||
221 | val); | ||
222 | if (ret) | ||
223 | return ret; | ||
224 | *val >>= chan->scan_type.shift; | ||
225 | val -= (1 << chan->scan_type.realbits) / 2; | ||
226 | return IIO_VAL_INT; | ||
227 | case IIO_CHAN_INFO_SCALE: | ||
228 | scale_uv = ((2 * st->vref) >> chan->scan_type.realbits) * 100; | ||
229 | *val = scale_uv / 100000; | ||
230 | *val2 = (scale_uv % 100000) * 10; | ||
231 | return IIO_VAL_INT_PLUS_MICRO; | ||
232 | default: | ||
233 | break; | ||
234 | } | ||
235 | |||
236 | return -EINVAL; | ||
237 | } | ||
238 | |||
239 | static const struct iio_info ad5380_info = { | ||
240 | .read_raw = ad5380_read_raw, | ||
241 | .write_raw = ad5380_write_raw, | ||
242 | .driver_module = THIS_MODULE, | ||
243 | }; | ||
244 | |||
245 | static struct iio_chan_spec_ext_info ad5380_ext_info[] = { | ||
246 | { | ||
247 | .name = "powerdown", | ||
248 | .read = ad5380_read_dac_powerdown, | ||
249 | .write = ad5380_write_dac_powerdown, | ||
250 | }, | ||
251 | IIO_ENUM("powerdown_mode", true, &ad5380_powerdown_mode_enum), | ||
252 | IIO_ENUM_AVAILABLE("powerdown_mode", &ad5380_powerdown_mode_enum), | ||
253 | { }, | ||
254 | }; | ||
255 | |||
256 | #define AD5380_CHANNEL(_bits) { \ | ||
257 | .type = IIO_VOLTAGE, \ | ||
258 | .indexed = 1, \ | ||
259 | .output = 1, \ | ||
260 | .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ | ||
261 | IIO_CHAN_INFO_SCALE_SHARED_BIT | \ | ||
262 | IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | \ | ||
263 | IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, \ | ||
264 | .scan_type = IIO_ST('u', (_bits), 16, 14 - (_bits)), \ | ||
265 | .ext_info = ad5380_ext_info, \ | ||
266 | } | ||
267 | |||
268 | static const struct ad5380_chip_info ad5380_chip_info_tbl[] = { | ||
269 | [ID_AD5380_3] = { | ||
270 | .channel_template = AD5380_CHANNEL(14), | ||
271 | .num_channels = 40, | ||
272 | .int_vref = 1250000, | ||
273 | }, | ||
274 | [ID_AD5380_5] = { | ||
275 | .channel_template = AD5380_CHANNEL(14), | ||
276 | .num_channels = 40, | ||
277 | .int_vref = 2500000, | ||
278 | }, | ||
279 | [ID_AD5381_3] = { | ||
280 | .channel_template = AD5380_CHANNEL(12), | ||
281 | .num_channels = 16, | ||
282 | .int_vref = 1250000, | ||
283 | }, | ||
284 | [ID_AD5381_5] = { | ||
285 | .channel_template = AD5380_CHANNEL(12), | ||
286 | .num_channels = 16, | ||
287 | .int_vref = 2500000, | ||
288 | }, | ||
289 | [ID_AD5382_3] = { | ||
290 | .channel_template = AD5380_CHANNEL(14), | ||
291 | .num_channels = 32, | ||
292 | .int_vref = 1250000, | ||
293 | }, | ||
294 | [ID_AD5382_5] = { | ||
295 | .channel_template = AD5380_CHANNEL(14), | ||
296 | .num_channels = 32, | ||
297 | .int_vref = 2500000, | ||
298 | }, | ||
299 | [ID_AD5383_3] = { | ||
300 | .channel_template = AD5380_CHANNEL(12), | ||
301 | .num_channels = 32, | ||
302 | .int_vref = 1250000, | ||
303 | }, | ||
304 | [ID_AD5383_5] = { | ||
305 | .channel_template = AD5380_CHANNEL(12), | ||
306 | .num_channels = 32, | ||
307 | .int_vref = 2500000, | ||
308 | }, | ||
309 | [ID_AD5390_3] = { | ||
310 | .channel_template = AD5380_CHANNEL(14), | ||
311 | .num_channels = 16, | ||
312 | .int_vref = 1250000, | ||
313 | }, | ||
314 | [ID_AD5390_5] = { | ||
315 | .channel_template = AD5380_CHANNEL(14), | ||
316 | .num_channels = 16, | ||
317 | .int_vref = 2500000, | ||
318 | }, | ||
319 | [ID_AD5391_3] = { | ||
320 | .channel_template = AD5380_CHANNEL(12), | ||
321 | .num_channels = 16, | ||
322 | .int_vref = 1250000, | ||
323 | }, | ||
324 | [ID_AD5391_5] = { | ||
325 | .channel_template = AD5380_CHANNEL(12), | ||
326 | .num_channels = 16, | ||
327 | .int_vref = 2500000, | ||
328 | }, | ||
329 | [ID_AD5392_3] = { | ||
330 | .channel_template = AD5380_CHANNEL(14), | ||
331 | .num_channels = 8, | ||
332 | .int_vref = 1250000, | ||
333 | }, | ||
334 | [ID_AD5392_5] = { | ||
335 | .channel_template = AD5380_CHANNEL(14), | ||
336 | .num_channels = 8, | ||
337 | .int_vref = 2500000, | ||
338 | }, | ||
339 | }; | ||
340 | |||
341 | static int __devinit ad5380_alloc_channels(struct iio_dev *indio_dev) | ||
342 | { | ||
343 | struct ad5380_state *st = iio_priv(indio_dev); | ||
344 | struct iio_chan_spec *channels; | ||
345 | unsigned int i; | ||
346 | |||
347 | channels = kcalloc(st->chip_info->num_channels, | ||
348 | sizeof(struct iio_chan_spec), GFP_KERNEL); | ||
349 | |||
350 | if (!channels) | ||
351 | return -ENOMEM; | ||
352 | |||
353 | for (i = 0; i < st->chip_info->num_channels; ++i) { | ||
354 | channels[i] = st->chip_info->channel_template; | ||
355 | channels[i].channel = i; | ||
356 | channels[i].address = i; | ||
357 | } | ||
358 | |||
359 | indio_dev->channels = channels; | ||
360 | |||
361 | return 0; | ||
362 | } | ||
363 | |||
364 | static int __devinit ad5380_probe(struct device *dev, struct regmap *regmap, | ||
365 | enum ad5380_type type, const char *name) | ||
366 | { | ||
367 | struct iio_dev *indio_dev; | ||
368 | struct ad5380_state *st; | ||
369 | unsigned int ctrl = 0; | ||
370 | int ret; | ||
371 | |||
372 | indio_dev = iio_device_alloc(sizeof(*st)); | ||
373 | if (indio_dev == NULL) { | ||
374 | dev_err(dev, "Failed to allocate iio device\n"); | ||
375 | ret = -ENOMEM; | ||
376 | goto error_regmap_exit; | ||
377 | } | ||
378 | |||
379 | st = iio_priv(indio_dev); | ||
380 | dev_set_drvdata(dev, indio_dev); | ||
381 | |||
382 | st->chip_info = &ad5380_chip_info_tbl[type]; | ||
383 | st->regmap = regmap; | ||
384 | |||
385 | indio_dev->dev.parent = dev; | ||
386 | indio_dev->name = name; | ||
387 | indio_dev->info = &ad5380_info; | ||
388 | indio_dev->modes = INDIO_DIRECT_MODE; | ||
389 | indio_dev->num_channels = st->chip_info->num_channels; | ||
390 | |||
391 | ret = ad5380_alloc_channels(indio_dev); | ||
392 | if (ret) { | ||
393 | dev_err(dev, "Failed to allocate channel spec: %d\n", ret); | ||
394 | goto error_free; | ||
395 | } | ||
396 | |||
397 | if (st->chip_info->int_vref == 2500000) | ||
398 | ctrl |= AD5380_CTRL_INT_VREF_2V5; | ||
399 | |||
400 | st->vref_reg = regulator_get(dev, "vref"); | ||
401 | if (!IS_ERR(st->vref_reg)) { | ||
402 | ret = regulator_enable(st->vref_reg); | ||
403 | if (ret) { | ||
404 | dev_err(dev, "Failed to enable vref regulators: %d\n", | ||
405 | ret); | ||
406 | goto error_free_reg; | ||
407 | } | ||
408 | |||
409 | st->vref = regulator_get_voltage(st->vref_reg); | ||
410 | } else { | ||
411 | st->vref = st->chip_info->int_vref; | ||
412 | ctrl |= AD5380_CTRL_INT_VREF_EN; | ||
413 | } | ||
414 | |||
415 | ret = regmap_write(st->regmap, AD5380_REG_SF_CTRL, ctrl); | ||
416 | if (ret) { | ||
417 | dev_err(dev, "Failed to write to device: %d\n", ret); | ||
418 | goto error_disable_reg; | ||
419 | } | ||
420 | |||
421 | ret = iio_device_register(indio_dev); | ||
422 | if (ret) { | ||
423 | dev_err(dev, "Failed to register iio device: %d\n", ret); | ||
424 | goto error_disable_reg; | ||
425 | } | ||
426 | |||
427 | return 0; | ||
428 | |||
429 | error_disable_reg: | ||
430 | if (!IS_ERR(st->vref_reg)) | ||
431 | regulator_disable(st->vref_reg); | ||
432 | error_free_reg: | ||
433 | if (!IS_ERR(st->vref_reg)) | ||
434 | regulator_put(st->vref_reg); | ||
435 | |||
436 | kfree(indio_dev->channels); | ||
437 | error_free: | ||
438 | iio_device_free(indio_dev); | ||
439 | error_regmap_exit: | ||
440 | regmap_exit(regmap); | ||
441 | |||
442 | return ret; | ||
443 | } | ||
444 | |||
445 | static int __devexit ad5380_remove(struct device *dev) | ||
446 | { | ||
447 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
448 | struct ad5380_state *st = iio_priv(indio_dev); | ||
449 | |||
450 | iio_device_unregister(indio_dev); | ||
451 | |||
452 | kfree(indio_dev->channels); | ||
453 | |||
454 | if (!IS_ERR(st->vref_reg)) { | ||
455 | regulator_disable(st->vref_reg); | ||
456 | regulator_put(st->vref_reg); | ||
457 | } | ||
458 | |||
459 | regmap_exit(st->regmap); | ||
460 | iio_device_free(indio_dev); | ||
461 | |||
462 | return 0; | ||
463 | } | ||
464 | |||
465 | static bool ad5380_reg_false(struct device *dev, unsigned int reg) | ||
466 | { | ||
467 | return false; | ||
468 | } | ||
469 | |||
470 | static const struct regmap_config ad5380_regmap_config = { | ||
471 | .reg_bits = 10, | ||
472 | .val_bits = 14, | ||
473 | |||
474 | .max_register = AD5380_REG_DATA(40), | ||
475 | .cache_type = REGCACHE_RBTREE, | ||
476 | |||
477 | .volatile_reg = ad5380_reg_false, | ||
478 | .readable_reg = ad5380_reg_false, | ||
479 | }; | ||
480 | |||
481 | #if IS_ENABLED(CONFIG_SPI_MASTER) | ||
482 | |||
483 | static int __devinit ad5380_spi_probe(struct spi_device *spi) | ||
484 | { | ||
485 | const struct spi_device_id *id = spi_get_device_id(spi); | ||
486 | struct regmap *regmap; | ||
487 | |||
488 | regmap = regmap_init_spi(spi, &ad5380_regmap_config); | ||
489 | |||
490 | if (IS_ERR(regmap)) | ||
491 | return PTR_ERR(regmap); | ||
492 | |||
493 | return ad5380_probe(&spi->dev, regmap, id->driver_data, id->name); | ||
494 | } | ||
495 | |||
496 | static int __devexit ad5380_spi_remove(struct spi_device *spi) | ||
497 | { | ||
498 | return ad5380_remove(&spi->dev); | ||
499 | } | ||
500 | |||
501 | static const struct spi_device_id ad5380_spi_ids[] = { | ||
502 | { "ad5380-3", ID_AD5380_3 }, | ||
503 | { "ad5380-5", ID_AD5380_5 }, | ||
504 | { "ad5381-3", ID_AD5381_3 }, | ||
505 | { "ad5381-5", ID_AD5381_5 }, | ||
506 | { "ad5382-3", ID_AD5382_3 }, | ||
507 | { "ad5382-5", ID_AD5382_5 }, | ||
508 | { "ad5383-3", ID_AD5383_3 }, | ||
509 | { "ad5383-5", ID_AD5383_5 }, | ||
510 | { "ad5384-3", ID_AD5380_3 }, | ||
511 | { "ad5384-5", ID_AD5380_5 }, | ||
512 | { "ad5390-3", ID_AD5390_3 }, | ||
513 | { "ad5390-5", ID_AD5390_5 }, | ||
514 | { "ad5391-3", ID_AD5391_3 }, | ||
515 | { "ad5391-5", ID_AD5391_5 }, | ||
516 | { "ad5392-3", ID_AD5392_3 }, | ||
517 | { "ad5392-5", ID_AD5392_5 }, | ||
518 | { } | ||
519 | }; | ||
520 | MODULE_DEVICE_TABLE(spi, ad5380_spi_ids); | ||
521 | |||
522 | static struct spi_driver ad5380_spi_driver = { | ||
523 | .driver = { | ||
524 | .name = "ad5380", | ||
525 | .owner = THIS_MODULE, | ||
526 | }, | ||
527 | .probe = ad5380_spi_probe, | ||
528 | .remove = __devexit_p(ad5380_spi_remove), | ||
529 | .id_table = ad5380_spi_ids, | ||
530 | }; | ||
531 | |||
532 | static inline int ad5380_spi_register_driver(void) | ||
533 | { | ||
534 | return spi_register_driver(&ad5380_spi_driver); | ||
535 | } | ||
536 | |||
537 | static inline void ad5380_spi_unregister_driver(void) | ||
538 | { | ||
539 | spi_unregister_driver(&ad5380_spi_driver); | ||
540 | } | ||
541 | |||
542 | #else | ||
543 | |||
544 | static inline int ad5380_spi_register_driver(void) | ||
545 | { | ||
546 | return 0; | ||
547 | } | ||
548 | |||
549 | static inline void ad5380_spi_unregister_driver(void) | ||
550 | { | ||
551 | } | ||
552 | |||
553 | #endif | ||
554 | |||
555 | #if IS_ENABLED(CONFIG_I2C) | ||
556 | |||
557 | static int __devinit ad5380_i2c_probe(struct i2c_client *i2c, | ||
558 | const struct i2c_device_id *id) | ||
559 | { | ||
560 | struct regmap *regmap; | ||
561 | |||
562 | regmap = regmap_init_i2c(i2c, &ad5380_regmap_config); | ||
563 | |||
564 | if (IS_ERR(regmap)) | ||
565 | return PTR_ERR(regmap); | ||
566 | |||
567 | return ad5380_probe(&i2c->dev, regmap, id->driver_data, id->name); | ||
568 | } | ||
569 | |||
570 | static int __devexit ad5380_i2c_remove(struct i2c_client *i2c) | ||
571 | { | ||
572 | return ad5380_remove(&i2c->dev); | ||
573 | } | ||
574 | |||
575 | static const struct i2c_device_id ad5380_i2c_ids[] = { | ||
576 | { "ad5380-3", ID_AD5380_3 }, | ||
577 | { "ad5380-5", ID_AD5380_5 }, | ||
578 | { "ad5381-3", ID_AD5381_3 }, | ||
579 | { "ad5381-5", ID_AD5381_5 }, | ||
580 | { "ad5382-3", ID_AD5382_3 }, | ||
581 | { "ad5382-5", ID_AD5382_5 }, | ||
582 | { "ad5383-3", ID_AD5383_3 }, | ||
583 | { "ad5383-5", ID_AD5383_5 }, | ||
584 | { "ad5384-3", ID_AD5380_3 }, | ||
585 | { "ad5384-5", ID_AD5380_5 }, | ||
586 | { "ad5390-3", ID_AD5390_3 }, | ||
587 | { "ad5390-5", ID_AD5390_5 }, | ||
588 | { "ad5391-3", ID_AD5391_3 }, | ||
589 | { "ad5391-5", ID_AD5391_5 }, | ||
590 | { "ad5392-3", ID_AD5392_3 }, | ||
591 | { "ad5392-5", ID_AD5392_5 }, | ||
592 | { } | ||
593 | }; | ||
594 | MODULE_DEVICE_TABLE(i2c, ad5380_i2c_ids); | ||
595 | |||
596 | static struct i2c_driver ad5380_i2c_driver = { | ||
597 | .driver = { | ||
598 | .name = "ad5380", | ||
599 | .owner = THIS_MODULE, | ||
600 | }, | ||
601 | .probe = ad5380_i2c_probe, | ||
602 | .remove = __devexit_p(ad5380_i2c_remove), | ||
603 | .id_table = ad5380_i2c_ids, | ||
604 | }; | ||
605 | |||
606 | static inline int ad5380_i2c_register_driver(void) | ||
607 | { | ||
608 | return i2c_add_driver(&ad5380_i2c_driver); | ||
609 | } | ||
610 | |||
611 | static inline void ad5380_i2c_unregister_driver(void) | ||
612 | { | ||
613 | i2c_del_driver(&ad5380_i2c_driver); | ||
614 | } | ||
615 | |||
616 | #else | ||
617 | |||
618 | static inline int ad5380_i2c_register_driver(void) | ||
619 | { | ||
620 | return 0; | ||
621 | } | ||
622 | |||
623 | static inline void ad5380_i2c_unregister_driver(void) | ||
624 | { | ||
625 | } | ||
626 | |||
627 | #endif | ||
628 | |||
629 | static int __init ad5380_spi_init(void) | ||
630 | { | ||
631 | int ret; | ||
632 | |||
633 | ret = ad5380_spi_register_driver(); | ||
634 | if (ret) | ||
635 | return ret; | ||
636 | |||
637 | ret = ad5380_i2c_register_driver(); | ||
638 | if (ret) { | ||
639 | ad5380_spi_unregister_driver(); | ||
640 | return ret; | ||
641 | } | ||
642 | |||
643 | return 0; | ||
644 | } | ||
645 | module_init(ad5380_spi_init); | ||
646 | |||
647 | static void __exit ad5380_spi_exit(void) | ||
648 | { | ||
649 | ad5380_i2c_unregister_driver(); | ||
650 | ad5380_spi_unregister_driver(); | ||
651 | |||
652 | } | ||
653 | module_exit(ad5380_spi_exit); | ||
654 | |||
655 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); | ||
656 | MODULE_DESCRIPTION("Analog Devices AD5380/81/82/83/84/90/91/92 DAC"); | ||
657 | MODULE_LICENSE("GPL v2"); | ||