1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * AD5446 SPI DAC driver |
4 | * |
5 | * Copyright 2010 Analog Devices Inc. |
6 | */ |
7 | |
8 | #include <linux/interrupt.h> |
9 | #include <linux/workqueue.h> |
10 | #include <linux/device.h> |
11 | #include <linux/kernel.h> |
12 | #include <linux/slab.h> |
13 | #include <linux/sysfs.h> |
14 | #include <linux/list.h> |
15 | #include <linux/spi/spi.h> |
16 | #include <linux/i2c.h> |
17 | #include <linux/regulator/consumer.h> |
18 | #include <linux/err.h> |
19 | #include <linux/module.h> |
20 | #include <linux/mod_devicetable.h> |
21 | |
22 | #include <linux/iio/iio.h> |
23 | #include <linux/iio/sysfs.h> |
24 | |
25 | #include <asm/unaligned.h> |
26 | |
27 | #define MODE_PWRDWN_1k 0x1 |
28 | #define MODE_PWRDWN_100k 0x2 |
29 | #define MODE_PWRDWN_TRISTATE 0x3 |
30 | |
31 | /** |
32 | * struct ad5446_state - driver instance specific data |
33 | * @dev: this device |
34 | * @chip_info: chip model specific constants, available modes etc |
35 | * @reg: supply regulator |
36 | * @vref_mv: actual reference voltage used |
37 | * @cached_val: store/retrieve values during power down |
38 | * @pwr_down_mode: power down mode (1k, 100k or tristate) |
39 | * @pwr_down: true if the device is in power down |
40 | * @lock: lock to protect the data buffer during write ops |
41 | */ |
42 | |
43 | struct ad5446_state { |
44 | struct device *dev; |
45 | const struct ad5446_chip_info *chip_info; |
46 | struct regulator *reg; |
47 | unsigned short vref_mv; |
48 | unsigned cached_val; |
49 | unsigned pwr_down_mode; |
50 | unsigned pwr_down; |
51 | struct mutex lock; |
52 | }; |
53 | |
54 | /** |
55 | * struct ad5446_chip_info - chip specific information |
56 | * @channel: channel spec for the DAC |
57 | * @int_vref_mv: AD5620/40/60: the internal reference voltage |
58 | * @write: chip specific helper function to write to the register |
59 | */ |
60 | |
61 | struct ad5446_chip_info { |
62 | struct iio_chan_spec channel; |
63 | u16 int_vref_mv; |
64 | int (*write)(struct ad5446_state *st, unsigned val); |
65 | }; |
66 | |
67 | static const char * const ad5446_powerdown_modes[] = { |
68 | "1kohm_to_gnd" , "100kohm_to_gnd" , "three_state" |
69 | }; |
70 | |
71 | static int ad5446_set_powerdown_mode(struct iio_dev *indio_dev, |
72 | const struct iio_chan_spec *chan, unsigned int mode) |
73 | { |
74 | struct ad5446_state *st = iio_priv(indio_dev); |
75 | |
76 | st->pwr_down_mode = mode + 1; |
77 | |
78 | return 0; |
79 | } |
80 | |
81 | static int ad5446_get_powerdown_mode(struct iio_dev *indio_dev, |
82 | const struct iio_chan_spec *chan) |
83 | { |
84 | struct ad5446_state *st = iio_priv(indio_dev); |
85 | |
86 | return st->pwr_down_mode - 1; |
87 | } |
88 | |
89 | static const struct iio_enum ad5446_powerdown_mode_enum = { |
90 | .items = ad5446_powerdown_modes, |
91 | .num_items = ARRAY_SIZE(ad5446_powerdown_modes), |
92 | .get = ad5446_get_powerdown_mode, |
93 | .set = ad5446_set_powerdown_mode, |
94 | }; |
95 | |
96 | static ssize_t ad5446_read_dac_powerdown(struct iio_dev *indio_dev, |
97 | uintptr_t private, |
98 | const struct iio_chan_spec *chan, |
99 | char *buf) |
100 | { |
101 | struct ad5446_state *st = iio_priv(indio_dev); |
102 | |
103 | return sysfs_emit(buf, fmt: "%d\n" , st->pwr_down); |
104 | } |
105 | |
106 | static ssize_t ad5446_write_dac_powerdown(struct iio_dev *indio_dev, |
107 | uintptr_t private, |
108 | const struct iio_chan_spec *chan, |
109 | const char *buf, size_t len) |
110 | { |
111 | struct ad5446_state *st = iio_priv(indio_dev); |
112 | unsigned int shift; |
113 | unsigned int val; |
114 | bool powerdown; |
115 | int ret; |
116 | |
117 | ret = kstrtobool(s: buf, res: &powerdown); |
118 | if (ret) |
119 | return ret; |
120 | |
121 | mutex_lock(&st->lock); |
122 | st->pwr_down = powerdown; |
123 | |
124 | if (st->pwr_down) { |
125 | shift = chan->scan_type.realbits + chan->scan_type.shift; |
126 | val = st->pwr_down_mode << shift; |
127 | } else { |
128 | val = st->cached_val; |
129 | } |
130 | |
131 | ret = st->chip_info->write(st, val); |
132 | mutex_unlock(lock: &st->lock); |
133 | |
134 | return ret ? ret : len; |
135 | } |
136 | |
137 | static const struct iio_chan_spec_ext_info ad5446_ext_info_powerdown[] = { |
138 | { |
139 | .name = "powerdown" , |
140 | .read = ad5446_read_dac_powerdown, |
141 | .write = ad5446_write_dac_powerdown, |
142 | .shared = IIO_SEPARATE, |
143 | }, |
144 | IIO_ENUM("powerdown_mode" , IIO_SEPARATE, &ad5446_powerdown_mode_enum), |
145 | IIO_ENUM_AVAILABLE("powerdown_mode" , IIO_SHARED_BY_TYPE, &ad5446_powerdown_mode_enum), |
146 | { }, |
147 | }; |
148 | |
149 | #define _AD5446_CHANNEL(bits, storage, _shift, ext) { \ |
150 | .type = IIO_VOLTAGE, \ |
151 | .indexed = 1, \ |
152 | .output = 1, \ |
153 | .channel = 0, \ |
154 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ |
155 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ |
156 | .scan_type = { \ |
157 | .sign = 'u', \ |
158 | .realbits = (bits), \ |
159 | .storagebits = (storage), \ |
160 | .shift = (_shift), \ |
161 | }, \ |
162 | .ext_info = (ext), \ |
163 | } |
164 | |
165 | #define AD5446_CHANNEL(bits, storage, shift) \ |
166 | _AD5446_CHANNEL(bits, storage, shift, NULL) |
167 | |
168 | #define AD5446_CHANNEL_POWERDOWN(bits, storage, shift) \ |
169 | _AD5446_CHANNEL(bits, storage, shift, ad5446_ext_info_powerdown) |
170 | |
171 | static int ad5446_read_raw(struct iio_dev *indio_dev, |
172 | struct iio_chan_spec const *chan, |
173 | int *val, |
174 | int *val2, |
175 | long m) |
176 | { |
177 | struct ad5446_state *st = iio_priv(indio_dev); |
178 | |
179 | switch (m) { |
180 | case IIO_CHAN_INFO_RAW: |
181 | *val = st->cached_val >> chan->scan_type.shift; |
182 | return IIO_VAL_INT; |
183 | case IIO_CHAN_INFO_SCALE: |
184 | *val = st->vref_mv; |
185 | *val2 = chan->scan_type.realbits; |
186 | return IIO_VAL_FRACTIONAL_LOG2; |
187 | } |
188 | return -EINVAL; |
189 | } |
190 | |
191 | static int ad5446_write_raw(struct iio_dev *indio_dev, |
192 | struct iio_chan_spec const *chan, |
193 | int val, |
194 | int val2, |
195 | long mask) |
196 | { |
197 | struct ad5446_state *st = iio_priv(indio_dev); |
198 | int ret = 0; |
199 | |
200 | switch (mask) { |
201 | case IIO_CHAN_INFO_RAW: |
202 | if (val >= (1 << chan->scan_type.realbits) || val < 0) |
203 | return -EINVAL; |
204 | |
205 | val <<= chan->scan_type.shift; |
206 | mutex_lock(&st->lock); |
207 | st->cached_val = val; |
208 | if (!st->pwr_down) |
209 | ret = st->chip_info->write(st, val); |
210 | mutex_unlock(lock: &st->lock); |
211 | break; |
212 | default: |
213 | ret = -EINVAL; |
214 | } |
215 | |
216 | return ret; |
217 | } |
218 | |
219 | static const struct iio_info ad5446_info = { |
220 | .read_raw = ad5446_read_raw, |
221 | .write_raw = ad5446_write_raw, |
222 | }; |
223 | |
224 | static int ad5446_probe(struct device *dev, const char *name, |
225 | const struct ad5446_chip_info *chip_info) |
226 | { |
227 | struct ad5446_state *st; |
228 | struct iio_dev *indio_dev; |
229 | struct regulator *reg; |
230 | int ret, voltage_uv = 0; |
231 | |
232 | reg = devm_regulator_get(dev, id: "vcc" ); |
233 | if (!IS_ERR(ptr: reg)) { |
234 | ret = regulator_enable(regulator: reg); |
235 | if (ret) |
236 | return ret; |
237 | |
238 | ret = regulator_get_voltage(regulator: reg); |
239 | if (ret < 0) |
240 | goto error_disable_reg; |
241 | |
242 | voltage_uv = ret; |
243 | } |
244 | |
245 | indio_dev = devm_iio_device_alloc(parent: dev, sizeof_priv: sizeof(*st)); |
246 | if (indio_dev == NULL) { |
247 | ret = -ENOMEM; |
248 | goto error_disable_reg; |
249 | } |
250 | st = iio_priv(indio_dev); |
251 | st->chip_info = chip_info; |
252 | |
253 | dev_set_drvdata(dev, data: indio_dev); |
254 | st->reg = reg; |
255 | st->dev = dev; |
256 | |
257 | indio_dev->name = name; |
258 | indio_dev->info = &ad5446_info; |
259 | indio_dev->modes = INDIO_DIRECT_MODE; |
260 | indio_dev->channels = &st->chip_info->channel; |
261 | indio_dev->num_channels = 1; |
262 | |
263 | mutex_init(&st->lock); |
264 | |
265 | st->pwr_down_mode = MODE_PWRDWN_1k; |
266 | |
267 | if (st->chip_info->int_vref_mv) |
268 | st->vref_mv = st->chip_info->int_vref_mv; |
269 | else if (voltage_uv) |
270 | st->vref_mv = voltage_uv / 1000; |
271 | else |
272 | dev_warn(dev, "reference voltage unspecified\n" ); |
273 | |
274 | ret = iio_device_register(indio_dev); |
275 | if (ret) |
276 | goto error_disable_reg; |
277 | |
278 | return 0; |
279 | |
280 | error_disable_reg: |
281 | if (!IS_ERR(ptr: reg)) |
282 | regulator_disable(regulator: reg); |
283 | return ret; |
284 | } |
285 | |
286 | static void ad5446_remove(struct device *dev) |
287 | { |
288 | struct iio_dev *indio_dev = dev_get_drvdata(dev); |
289 | struct ad5446_state *st = iio_priv(indio_dev); |
290 | |
291 | iio_device_unregister(indio_dev); |
292 | if (!IS_ERR(ptr: st->reg)) |
293 | regulator_disable(regulator: st->reg); |
294 | } |
295 | |
296 | #if IS_ENABLED(CONFIG_SPI_MASTER) |
297 | |
298 | static int ad5446_write(struct ad5446_state *st, unsigned val) |
299 | { |
300 | struct spi_device *spi = to_spi_device(dev: st->dev); |
301 | __be16 data = cpu_to_be16(val); |
302 | |
303 | return spi_write(spi, buf: &data, len: sizeof(data)); |
304 | } |
305 | |
306 | static int ad5660_write(struct ad5446_state *st, unsigned val) |
307 | { |
308 | struct spi_device *spi = to_spi_device(dev: st->dev); |
309 | uint8_t data[3]; |
310 | |
311 | put_unaligned_be24(val, p: &data[0]); |
312 | |
313 | return spi_write(spi, buf: data, len: sizeof(data)); |
314 | } |
315 | |
316 | /* |
317 | * ad5446_supported_spi_device_ids: |
318 | * The AD5620/40/60 parts are available in different fixed internal reference |
319 | * voltage options. The actual part numbers may look differently |
320 | * (and a bit cryptic), however this style is used to make clear which |
321 | * parts are supported here. |
322 | */ |
323 | enum ad5446_supported_spi_device_ids { |
324 | ID_AD5300, |
325 | ID_AD5310, |
326 | ID_AD5320, |
327 | ID_AD5444, |
328 | ID_AD5446, |
329 | ID_AD5450, |
330 | ID_AD5451, |
331 | ID_AD5541A, |
332 | ID_AD5512A, |
333 | ID_AD5553, |
334 | ID_AD5600, |
335 | ID_AD5601, |
336 | ID_AD5611, |
337 | ID_AD5621, |
338 | ID_AD5641, |
339 | ID_AD5620_2500, |
340 | ID_AD5620_1250, |
341 | ID_AD5640_2500, |
342 | ID_AD5640_1250, |
343 | ID_AD5660_2500, |
344 | ID_AD5660_1250, |
345 | ID_AD5662, |
346 | }; |
347 | |
348 | static const struct ad5446_chip_info ad5446_spi_chip_info[] = { |
349 | [ID_AD5300] = { |
350 | .channel = AD5446_CHANNEL_POWERDOWN(8, 16, 4), |
351 | .write = ad5446_write, |
352 | }, |
353 | [ID_AD5310] = { |
354 | .channel = AD5446_CHANNEL_POWERDOWN(10, 16, 2), |
355 | .write = ad5446_write, |
356 | }, |
357 | [ID_AD5320] = { |
358 | .channel = AD5446_CHANNEL_POWERDOWN(12, 16, 0), |
359 | .write = ad5446_write, |
360 | }, |
361 | [ID_AD5444] = { |
362 | .channel = AD5446_CHANNEL(12, 16, 2), |
363 | .write = ad5446_write, |
364 | }, |
365 | [ID_AD5446] = { |
366 | .channel = AD5446_CHANNEL(14, 16, 0), |
367 | .write = ad5446_write, |
368 | }, |
369 | [ID_AD5450] = { |
370 | .channel = AD5446_CHANNEL(8, 16, 6), |
371 | .write = ad5446_write, |
372 | }, |
373 | [ID_AD5451] = { |
374 | .channel = AD5446_CHANNEL(10, 16, 4), |
375 | .write = ad5446_write, |
376 | }, |
377 | [ID_AD5541A] = { |
378 | .channel = AD5446_CHANNEL(16, 16, 0), |
379 | .write = ad5446_write, |
380 | }, |
381 | [ID_AD5512A] = { |
382 | .channel = AD5446_CHANNEL(12, 16, 4), |
383 | .write = ad5446_write, |
384 | }, |
385 | [ID_AD5553] = { |
386 | .channel = AD5446_CHANNEL(14, 16, 0), |
387 | .write = ad5446_write, |
388 | }, |
389 | [ID_AD5600] = { |
390 | .channel = AD5446_CHANNEL(16, 16, 0), |
391 | .write = ad5446_write, |
392 | }, |
393 | [ID_AD5601] = { |
394 | .channel = AD5446_CHANNEL_POWERDOWN(8, 16, 6), |
395 | .write = ad5446_write, |
396 | }, |
397 | [ID_AD5611] = { |
398 | .channel = AD5446_CHANNEL_POWERDOWN(10, 16, 4), |
399 | .write = ad5446_write, |
400 | }, |
401 | [ID_AD5621] = { |
402 | .channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2), |
403 | .write = ad5446_write, |
404 | }, |
405 | [ID_AD5641] = { |
406 | .channel = AD5446_CHANNEL_POWERDOWN(14, 16, 0), |
407 | .write = ad5446_write, |
408 | }, |
409 | [ID_AD5620_2500] = { |
410 | .channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2), |
411 | .int_vref_mv = 2500, |
412 | .write = ad5446_write, |
413 | }, |
414 | [ID_AD5620_1250] = { |
415 | .channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2), |
416 | .int_vref_mv = 1250, |
417 | .write = ad5446_write, |
418 | }, |
419 | [ID_AD5640_2500] = { |
420 | .channel = AD5446_CHANNEL_POWERDOWN(14, 16, 0), |
421 | .int_vref_mv = 2500, |
422 | .write = ad5446_write, |
423 | }, |
424 | [ID_AD5640_1250] = { |
425 | .channel = AD5446_CHANNEL_POWERDOWN(14, 16, 0), |
426 | .int_vref_mv = 1250, |
427 | .write = ad5446_write, |
428 | }, |
429 | [ID_AD5660_2500] = { |
430 | .channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0), |
431 | .int_vref_mv = 2500, |
432 | .write = ad5660_write, |
433 | }, |
434 | [ID_AD5660_1250] = { |
435 | .channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0), |
436 | .int_vref_mv = 1250, |
437 | .write = ad5660_write, |
438 | }, |
439 | [ID_AD5662] = { |
440 | .channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0), |
441 | .write = ad5660_write, |
442 | }, |
443 | }; |
444 | |
445 | static const struct spi_device_id ad5446_spi_ids[] = { |
446 | {"ad5300" , ID_AD5300}, |
447 | {"ad5310" , ID_AD5310}, |
448 | {"ad5320" , ID_AD5320}, |
449 | {"ad5444" , ID_AD5444}, |
450 | {"ad5446" , ID_AD5446}, |
451 | {"ad5450" , ID_AD5450}, |
452 | {"ad5451" , ID_AD5451}, |
453 | {"ad5452" , ID_AD5444}, /* ad5452 is compatible to the ad5444 */ |
454 | {"ad5453" , ID_AD5446}, /* ad5453 is compatible to the ad5446 */ |
455 | {"ad5512a" , ID_AD5512A}, |
456 | {"ad5541a" , ID_AD5541A}, |
457 | {"ad5542a" , ID_AD5541A}, /* ad5541a and ad5542a are compatible */ |
458 | {"ad5543" , ID_AD5541A}, /* ad5541a and ad5543 are compatible */ |
459 | {"ad5553" , ID_AD5553}, |
460 | {"ad5600" , ID_AD5600}, |
461 | {"ad5601" , ID_AD5601}, |
462 | {"ad5611" , ID_AD5611}, |
463 | {"ad5621" , ID_AD5621}, |
464 | {"ad5641" , ID_AD5641}, |
465 | {"ad5620-2500" , ID_AD5620_2500}, /* AD5620/40/60: */ |
466 | {"ad5620-1250" , ID_AD5620_1250}, /* part numbers may look differently */ |
467 | {"ad5640-2500" , ID_AD5640_2500}, |
468 | {"ad5640-1250" , ID_AD5640_1250}, |
469 | {"ad5660-2500" , ID_AD5660_2500}, |
470 | {"ad5660-1250" , ID_AD5660_1250}, |
471 | {"ad5662" , ID_AD5662}, |
472 | {"dac081s101" , ID_AD5300}, /* compatible Texas Instruments chips */ |
473 | {"dac101s101" , ID_AD5310}, |
474 | {"dac121s101" , ID_AD5320}, |
475 | {"dac7512" , ID_AD5320}, |
476 | {} |
477 | }; |
478 | MODULE_DEVICE_TABLE(spi, ad5446_spi_ids); |
479 | |
480 | static const struct of_device_id ad5446_of_ids[] = { |
481 | { .compatible = "ti,dac7512" }, |
482 | { } |
483 | }; |
484 | MODULE_DEVICE_TABLE(of, ad5446_of_ids); |
485 | |
486 | static int ad5446_spi_probe(struct spi_device *spi) |
487 | { |
488 | const struct spi_device_id *id = spi_get_device_id(sdev: spi); |
489 | |
490 | return ad5446_probe(dev: &spi->dev, name: id->name, |
491 | chip_info: &ad5446_spi_chip_info[id->driver_data]); |
492 | } |
493 | |
494 | static void ad5446_spi_remove(struct spi_device *spi) |
495 | { |
496 | ad5446_remove(dev: &spi->dev); |
497 | } |
498 | |
499 | static struct spi_driver ad5446_spi_driver = { |
500 | .driver = { |
501 | .name = "ad5446" , |
502 | .of_match_table = ad5446_of_ids, |
503 | }, |
504 | .probe = ad5446_spi_probe, |
505 | .remove = ad5446_spi_remove, |
506 | .id_table = ad5446_spi_ids, |
507 | }; |
508 | |
509 | static int __init ad5446_spi_register_driver(void) |
510 | { |
511 | return spi_register_driver(&ad5446_spi_driver); |
512 | } |
513 | |
514 | static void ad5446_spi_unregister_driver(void) |
515 | { |
516 | spi_unregister_driver(sdrv: &ad5446_spi_driver); |
517 | } |
518 | |
519 | #else |
520 | |
521 | static inline int ad5446_spi_register_driver(void) { return 0; } |
522 | static inline void ad5446_spi_unregister_driver(void) { } |
523 | |
524 | #endif |
525 | |
526 | #if IS_ENABLED(CONFIG_I2C) |
527 | |
528 | static int ad5622_write(struct ad5446_state *st, unsigned val) |
529 | { |
530 | struct i2c_client *client = to_i2c_client(st->dev); |
531 | __be16 data = cpu_to_be16(val); |
532 | int ret; |
533 | |
534 | ret = i2c_master_send(client, buf: (char *)&data, count: sizeof(data)); |
535 | if (ret < 0) |
536 | return ret; |
537 | if (ret != sizeof(data)) |
538 | return -EIO; |
539 | |
540 | return 0; |
541 | } |
542 | |
543 | /* |
544 | * ad5446_supported_i2c_device_ids: |
545 | * The AD5620/40/60 parts are available in different fixed internal reference |
546 | * voltage options. The actual part numbers may look differently |
547 | * (and a bit cryptic), however this style is used to make clear which |
548 | * parts are supported here. |
549 | */ |
550 | enum ad5446_supported_i2c_device_ids { |
551 | ID_AD5602, |
552 | ID_AD5612, |
553 | ID_AD5622, |
554 | }; |
555 | |
556 | static const struct ad5446_chip_info ad5446_i2c_chip_info[] = { |
557 | [ID_AD5602] = { |
558 | .channel = AD5446_CHANNEL_POWERDOWN(8, 16, 4), |
559 | .write = ad5622_write, |
560 | }, |
561 | [ID_AD5612] = { |
562 | .channel = AD5446_CHANNEL_POWERDOWN(10, 16, 2), |
563 | .write = ad5622_write, |
564 | }, |
565 | [ID_AD5622] = { |
566 | .channel = AD5446_CHANNEL_POWERDOWN(12, 16, 0), |
567 | .write = ad5622_write, |
568 | }, |
569 | }; |
570 | |
571 | static int ad5446_i2c_probe(struct i2c_client *i2c) |
572 | { |
573 | const struct i2c_device_id *id = i2c_client_get_device_id(client: i2c); |
574 | return ad5446_probe(dev: &i2c->dev, name: id->name, |
575 | chip_info: &ad5446_i2c_chip_info[id->driver_data]); |
576 | } |
577 | |
578 | static void ad5446_i2c_remove(struct i2c_client *i2c) |
579 | { |
580 | ad5446_remove(dev: &i2c->dev); |
581 | } |
582 | |
583 | static const struct i2c_device_id ad5446_i2c_ids[] = { |
584 | {"ad5301" , ID_AD5602}, |
585 | {"ad5311" , ID_AD5612}, |
586 | {"ad5321" , ID_AD5622}, |
587 | {"ad5602" , ID_AD5602}, |
588 | {"ad5612" , ID_AD5612}, |
589 | {"ad5622" , ID_AD5622}, |
590 | {} |
591 | }; |
592 | MODULE_DEVICE_TABLE(i2c, ad5446_i2c_ids); |
593 | |
594 | static struct i2c_driver ad5446_i2c_driver = { |
595 | .driver = { |
596 | .name = "ad5446" , |
597 | }, |
598 | .probe = ad5446_i2c_probe, |
599 | .remove = ad5446_i2c_remove, |
600 | .id_table = ad5446_i2c_ids, |
601 | }; |
602 | |
603 | static int __init ad5446_i2c_register_driver(void) |
604 | { |
605 | return i2c_add_driver(&ad5446_i2c_driver); |
606 | } |
607 | |
608 | static void __exit ad5446_i2c_unregister_driver(void) |
609 | { |
610 | i2c_del_driver(driver: &ad5446_i2c_driver); |
611 | } |
612 | |
613 | #else |
614 | |
615 | static inline int ad5446_i2c_register_driver(void) { return 0; } |
616 | static inline void ad5446_i2c_unregister_driver(void) { } |
617 | |
618 | #endif |
619 | |
620 | static int __init ad5446_init(void) |
621 | { |
622 | int ret; |
623 | |
624 | ret = ad5446_spi_register_driver(); |
625 | if (ret) |
626 | return ret; |
627 | |
628 | ret = ad5446_i2c_register_driver(); |
629 | if (ret) { |
630 | ad5446_spi_unregister_driver(); |
631 | return ret; |
632 | } |
633 | |
634 | return 0; |
635 | } |
636 | module_init(ad5446_init); |
637 | |
638 | static void __exit ad5446_exit(void) |
639 | { |
640 | ad5446_i2c_unregister_driver(); |
641 | ad5446_spi_unregister_driver(); |
642 | } |
643 | module_exit(ad5446_exit); |
644 | |
645 | MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>" ); |
646 | MODULE_DESCRIPTION("Analog Devices AD5444/AD5446 DAC" ); |
647 | MODULE_LICENSE("GPL v2" ); |
648 | |