diff options
author | Lars-Peter Clausen <lars@metafoo.de> | 2012-06-04 05:36:28 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-06-05 01:02:25 -0400 |
commit | dbdc025bb239ce62c9b4d28c459a98f22ce9ec0a (patch) | |
tree | 2858c04b9d18852c1a4f4ca1c60c8e00b6180470 /drivers/iio/dac/ad5791.c | |
parent | 20374d1a36df3e20cd6742ba376684e5506254a8 (diff) |
staging:iio: Move DAC drivers out of staging
The IIO DAC drivers are in a reasonably good shape. They all make use of channel
spec and non of them provides non-documented sysfs attributes. Code style should
be OK as well, both checkpatch and coccicheck only report trivial issues.
So lets move the whole folder out of staging.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Acked-by: Jonathan Cameron <jic23@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/iio/dac/ad5791.c')
-rw-r--r-- | drivers/iio/dac/ad5791.c | 485 |
1 files changed, 485 insertions, 0 deletions
diff --git a/drivers/iio/dac/ad5791.c b/drivers/iio/dac/ad5791.c new file mode 100644 index 000000000000..2bd2e37280ff --- /dev/null +++ b/drivers/iio/dac/ad5791.c | |||
@@ -0,0 +1,485 @@ | |||
1 | /* | ||
2 | * AD5760, AD5780, AD5781, AD5790, AD5791 Voltage Output Digital to Analog | ||
3 | * Converter | ||
4 | * | ||
5 | * Copyright 2011 Analog Devices Inc. | ||
6 | * | ||
7 | * Licensed under the GPL-2. | ||
8 | */ | ||
9 | |||
10 | #include <linux/interrupt.h> | ||
11 | #include <linux/fs.h> | ||
12 | #include <linux/device.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/spi/spi.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include <linux/sysfs.h> | ||
17 | #include <linux/regulator/consumer.h> | ||
18 | #include <linux/module.h> | ||
19 | |||
20 | #include <linux/iio/iio.h> | ||
21 | #include <linux/iio/sysfs.h> | ||
22 | #include <linux/iio/dac/ad5791.h> | ||
23 | |||
24 | #define AD5791_RES_MASK(x) ((1 << (x)) - 1) | ||
25 | #define AD5791_DAC_MASK AD5791_RES_MASK(20) | ||
26 | #define AD5791_DAC_MSB (1 << 19) | ||
27 | |||
28 | #define AD5791_CMD_READ (1 << 23) | ||
29 | #define AD5791_CMD_WRITE (0 << 23) | ||
30 | #define AD5791_ADDR(addr) ((addr) << 20) | ||
31 | |||
32 | /* Registers */ | ||
33 | #define AD5791_ADDR_NOOP 0 | ||
34 | #define AD5791_ADDR_DAC0 1 | ||
35 | #define AD5791_ADDR_CTRL 2 | ||
36 | #define AD5791_ADDR_CLRCODE 3 | ||
37 | #define AD5791_ADDR_SW_CTRL 4 | ||
38 | |||
39 | /* Control Register */ | ||
40 | #define AD5791_CTRL_RBUF (1 << 1) | ||
41 | #define AD5791_CTRL_OPGND (1 << 2) | ||
42 | #define AD5791_CTRL_DACTRI (1 << 3) | ||
43 | #define AD5791_CTRL_BIN2SC (1 << 4) | ||
44 | #define AD5791_CTRL_SDODIS (1 << 5) | ||
45 | #define AD5761_CTRL_LINCOMP(x) ((x) << 6) | ||
46 | |||
47 | #define AD5791_LINCOMP_0_10 0 | ||
48 | #define AD5791_LINCOMP_10_12 1 | ||
49 | #define AD5791_LINCOMP_12_16 2 | ||
50 | #define AD5791_LINCOMP_16_19 3 | ||
51 | #define AD5791_LINCOMP_19_20 12 | ||
52 | |||
53 | #define AD5780_LINCOMP_0_10 0 | ||
54 | #define AD5780_LINCOMP_10_20 12 | ||
55 | |||
56 | /* Software Control Register */ | ||
57 | #define AD5791_SWCTRL_LDAC (1 << 0) | ||
58 | #define AD5791_SWCTRL_CLR (1 << 1) | ||
59 | #define AD5791_SWCTRL_RESET (1 << 2) | ||
60 | |||
61 | #define AD5791_DAC_PWRDN_6K 0 | ||
62 | #define AD5791_DAC_PWRDN_3STATE 1 | ||
63 | |||
64 | /** | ||
65 | * struct ad5791_chip_info - chip specific information | ||
66 | * @get_lin_comp: function pointer to the device specific function | ||
67 | */ | ||
68 | |||
69 | struct ad5791_chip_info { | ||
70 | int (*get_lin_comp) (unsigned int span); | ||
71 | }; | ||
72 | |||
73 | /** | ||
74 | * struct ad5791_state - driver instance specific data | ||
75 | * @us: spi_device | ||
76 | * @reg_vdd: positive supply regulator | ||
77 | * @reg_vss: negative supply regulator | ||
78 | * @chip_info: chip model specific constants | ||
79 | * @vref_mv: actual reference voltage used | ||
80 | * @vref_neg_mv: voltage of the negative supply | ||
81 | * @pwr_down_mode current power down mode | ||
82 | */ | ||
83 | |||
84 | struct ad5791_state { | ||
85 | struct spi_device *spi; | ||
86 | struct regulator *reg_vdd; | ||
87 | struct regulator *reg_vss; | ||
88 | const struct ad5791_chip_info *chip_info; | ||
89 | unsigned short vref_mv; | ||
90 | unsigned int vref_neg_mv; | ||
91 | unsigned ctrl; | ||
92 | unsigned pwr_down_mode; | ||
93 | bool pwr_down; | ||
94 | }; | ||
95 | |||
96 | /** | ||
97 | * ad5791_supported_device_ids: | ||
98 | */ | ||
99 | |||
100 | enum ad5791_supported_device_ids { | ||
101 | ID_AD5760, | ||
102 | ID_AD5780, | ||
103 | ID_AD5781, | ||
104 | ID_AD5791, | ||
105 | }; | ||
106 | |||
107 | static int ad5791_spi_write(struct spi_device *spi, u8 addr, u32 val) | ||
108 | { | ||
109 | union { | ||
110 | u32 d32; | ||
111 | u8 d8[4]; | ||
112 | } data; | ||
113 | |||
114 | data.d32 = cpu_to_be32(AD5791_CMD_WRITE | | ||
115 | AD5791_ADDR(addr) | | ||
116 | (val & AD5791_DAC_MASK)); | ||
117 | |||
118 | return spi_write(spi, &data.d8[1], 3); | ||
119 | } | ||
120 | |||
121 | static int ad5791_spi_read(struct spi_device *spi, u8 addr, u32 *val) | ||
122 | { | ||
123 | union { | ||
124 | u32 d32; | ||
125 | u8 d8[4]; | ||
126 | } data[3]; | ||
127 | int ret; | ||
128 | struct spi_message msg; | ||
129 | struct spi_transfer xfers[] = { | ||
130 | { | ||
131 | .tx_buf = &data[0].d8[1], | ||
132 | .bits_per_word = 8, | ||
133 | .len = 3, | ||
134 | .cs_change = 1, | ||
135 | }, { | ||
136 | .tx_buf = &data[1].d8[1], | ||
137 | .rx_buf = &data[2].d8[1], | ||
138 | .bits_per_word = 8, | ||
139 | .len = 3, | ||
140 | }, | ||
141 | }; | ||
142 | |||
143 | data[0].d32 = cpu_to_be32(AD5791_CMD_READ | | ||
144 | AD5791_ADDR(addr)); | ||
145 | data[1].d32 = cpu_to_be32(AD5791_ADDR(AD5791_ADDR_NOOP)); | ||
146 | |||
147 | spi_message_init(&msg); | ||
148 | spi_message_add_tail(&xfers[0], &msg); | ||
149 | spi_message_add_tail(&xfers[1], &msg); | ||
150 | ret = spi_sync(spi, &msg); | ||
151 | |||
152 | *val = be32_to_cpu(data[2].d32); | ||
153 | |||
154 | return ret; | ||
155 | } | ||
156 | |||
157 | static const char * const ad5791_powerdown_modes[] = { | ||
158 | "6kohm_to_gnd", | ||
159 | "three_state", | ||
160 | }; | ||
161 | |||
162 | static int ad5791_get_powerdown_mode(struct iio_dev *indio_dev, | ||
163 | const struct iio_chan_spec *chan) | ||
164 | { | ||
165 | struct ad5791_state *st = iio_priv(indio_dev); | ||
166 | |||
167 | return st->pwr_down_mode; | ||
168 | } | ||
169 | |||
170 | static int ad5791_set_powerdown_mode(struct iio_dev *indio_dev, | ||
171 | const struct iio_chan_spec *chan, unsigned int mode) | ||
172 | { | ||
173 | struct ad5791_state *st = iio_priv(indio_dev); | ||
174 | |||
175 | st->pwr_down_mode = mode; | ||
176 | |||
177 | return 0; | ||
178 | } | ||
179 | |||
180 | static const struct iio_enum ad5791_powerdown_mode_enum = { | ||
181 | .items = ad5791_powerdown_modes, | ||
182 | .num_items = ARRAY_SIZE(ad5791_powerdown_modes), | ||
183 | .get = ad5791_get_powerdown_mode, | ||
184 | .set = ad5791_set_powerdown_mode, | ||
185 | }; | ||
186 | |||
187 | static ssize_t ad5791_read_dac_powerdown(struct iio_dev *indio_dev, | ||
188 | uintptr_t private, const struct iio_chan_spec *chan, char *buf) | ||
189 | { | ||
190 | struct ad5791_state *st = iio_priv(indio_dev); | ||
191 | |||
192 | return sprintf(buf, "%d\n", st->pwr_down); | ||
193 | } | ||
194 | |||
195 | static ssize_t ad5791_write_dac_powerdown(struct iio_dev *indio_dev, | ||
196 | uintptr_t private, const struct iio_chan_spec *chan, const char *buf, | ||
197 | size_t len) | ||
198 | { | ||
199 | bool pwr_down; | ||
200 | int ret; | ||
201 | struct ad5791_state *st = iio_priv(indio_dev); | ||
202 | |||
203 | ret = strtobool(buf, &pwr_down); | ||
204 | if (ret) | ||
205 | return ret; | ||
206 | |||
207 | if (!pwr_down) { | ||
208 | st->ctrl &= ~(AD5791_CTRL_OPGND | AD5791_CTRL_DACTRI); | ||
209 | } else { | ||
210 | if (st->pwr_down_mode == AD5791_DAC_PWRDN_6K) | ||
211 | st->ctrl |= AD5791_CTRL_OPGND; | ||
212 | else if (st->pwr_down_mode == AD5791_DAC_PWRDN_3STATE) | ||
213 | st->ctrl |= AD5791_CTRL_DACTRI; | ||
214 | } | ||
215 | st->pwr_down = pwr_down; | ||
216 | |||
217 | ret = ad5791_spi_write(st->spi, AD5791_ADDR_CTRL, st->ctrl); | ||
218 | |||
219 | return ret ? ret : len; | ||
220 | } | ||
221 | |||
222 | static int ad5791_get_lin_comp(unsigned int span) | ||
223 | { | ||
224 | if (span <= 10000) | ||
225 | return AD5791_LINCOMP_0_10; | ||
226 | else if (span <= 12000) | ||
227 | return AD5791_LINCOMP_10_12; | ||
228 | else if (span <= 16000) | ||
229 | return AD5791_LINCOMP_12_16; | ||
230 | else if (span <= 19000) | ||
231 | return AD5791_LINCOMP_16_19; | ||
232 | else | ||
233 | return AD5791_LINCOMP_19_20; | ||
234 | } | ||
235 | |||
236 | static int ad5780_get_lin_comp(unsigned int span) | ||
237 | { | ||
238 | if (span <= 10000) | ||
239 | return AD5780_LINCOMP_0_10; | ||
240 | else | ||
241 | return AD5780_LINCOMP_10_20; | ||
242 | } | ||
243 | static const struct ad5791_chip_info ad5791_chip_info_tbl[] = { | ||
244 | [ID_AD5760] = { | ||
245 | .get_lin_comp = ad5780_get_lin_comp, | ||
246 | }, | ||
247 | [ID_AD5780] = { | ||
248 | .get_lin_comp = ad5780_get_lin_comp, | ||
249 | }, | ||
250 | [ID_AD5781] = { | ||
251 | .get_lin_comp = ad5791_get_lin_comp, | ||
252 | }, | ||
253 | [ID_AD5791] = { | ||
254 | .get_lin_comp = ad5791_get_lin_comp, | ||
255 | }, | ||
256 | }; | ||
257 | |||
258 | static int ad5791_read_raw(struct iio_dev *indio_dev, | ||
259 | struct iio_chan_spec const *chan, | ||
260 | int *val, | ||
261 | int *val2, | ||
262 | long m) | ||
263 | { | ||
264 | struct ad5791_state *st = iio_priv(indio_dev); | ||
265 | u64 val64; | ||
266 | int ret; | ||
267 | |||
268 | switch (m) { | ||
269 | case IIO_CHAN_INFO_RAW: | ||
270 | ret = ad5791_spi_read(st->spi, chan->address, val); | ||
271 | if (ret) | ||
272 | return ret; | ||
273 | *val &= AD5791_DAC_MASK; | ||
274 | *val >>= chan->scan_type.shift; | ||
275 | return IIO_VAL_INT; | ||
276 | case IIO_CHAN_INFO_SCALE: | ||
277 | *val = 0; | ||
278 | *val2 = (((u64)st->vref_mv) * 1000000ULL) >> chan->scan_type.realbits; | ||
279 | return IIO_VAL_INT_PLUS_MICRO; | ||
280 | case IIO_CHAN_INFO_OFFSET: | ||
281 | val64 = (((u64)st->vref_neg_mv) << chan->scan_type.realbits); | ||
282 | do_div(val64, st->vref_mv); | ||
283 | *val = -val64; | ||
284 | return IIO_VAL_INT; | ||
285 | default: | ||
286 | return -EINVAL; | ||
287 | } | ||
288 | |||
289 | }; | ||
290 | |||
291 | static const struct iio_chan_spec_ext_info ad5791_ext_info[] = { | ||
292 | { | ||
293 | .name = "powerdown", | ||
294 | .shared = true, | ||
295 | .read = ad5791_read_dac_powerdown, | ||
296 | .write = ad5791_write_dac_powerdown, | ||
297 | }, | ||
298 | IIO_ENUM("powerdown_mode", true, &ad5791_powerdown_mode_enum), | ||
299 | IIO_ENUM_AVAILABLE("powerdown_mode", &ad5791_powerdown_mode_enum), | ||
300 | { }, | ||
301 | }; | ||
302 | |||
303 | #define AD5791_CHAN(bits, shift) { \ | ||
304 | .type = IIO_VOLTAGE, \ | ||
305 | .output = 1, \ | ||
306 | .indexed = 1, \ | ||
307 | .address = AD5791_ADDR_DAC0, \ | ||
308 | .channel = 0, \ | ||
309 | .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ | ||
310 | IIO_CHAN_INFO_SCALE_SHARED_BIT | \ | ||
311 | IIO_CHAN_INFO_OFFSET_SHARED_BIT, \ | ||
312 | .scan_type = IIO_ST('u', bits, 24, shift), \ | ||
313 | .ext_info = ad5791_ext_info, \ | ||
314 | } | ||
315 | |||
316 | static const struct iio_chan_spec ad5791_channels[] = { | ||
317 | [ID_AD5760] = AD5791_CHAN(16, 4), | ||
318 | [ID_AD5780] = AD5791_CHAN(18, 2), | ||
319 | [ID_AD5781] = AD5791_CHAN(18, 2), | ||
320 | [ID_AD5791] = AD5791_CHAN(20, 0) | ||
321 | }; | ||
322 | |||
323 | static int ad5791_write_raw(struct iio_dev *indio_dev, | ||
324 | struct iio_chan_spec const *chan, | ||
325 | int val, | ||
326 | int val2, | ||
327 | long mask) | ||
328 | { | ||
329 | struct ad5791_state *st = iio_priv(indio_dev); | ||
330 | |||
331 | switch (mask) { | ||
332 | case IIO_CHAN_INFO_RAW: | ||
333 | val &= AD5791_RES_MASK(chan->scan_type.realbits); | ||
334 | val <<= chan->scan_type.shift; | ||
335 | |||
336 | return ad5791_spi_write(st->spi, chan->address, val); | ||
337 | |||
338 | default: | ||
339 | return -EINVAL; | ||
340 | } | ||
341 | } | ||
342 | |||
343 | static const struct iio_info ad5791_info = { | ||
344 | .read_raw = &ad5791_read_raw, | ||
345 | .write_raw = &ad5791_write_raw, | ||
346 | .driver_module = THIS_MODULE, | ||
347 | }; | ||
348 | |||
349 | static int __devinit ad5791_probe(struct spi_device *spi) | ||
350 | { | ||
351 | struct ad5791_platform_data *pdata = spi->dev.platform_data; | ||
352 | struct iio_dev *indio_dev; | ||
353 | struct ad5791_state *st; | ||
354 | int ret, pos_voltage_uv = 0, neg_voltage_uv = 0; | ||
355 | |||
356 | indio_dev = iio_device_alloc(sizeof(*st)); | ||
357 | if (indio_dev == NULL) { | ||
358 | ret = -ENOMEM; | ||
359 | goto error_ret; | ||
360 | } | ||
361 | st = iio_priv(indio_dev); | ||
362 | st->reg_vdd = regulator_get(&spi->dev, "vdd"); | ||
363 | if (!IS_ERR(st->reg_vdd)) { | ||
364 | ret = regulator_enable(st->reg_vdd); | ||
365 | if (ret) | ||
366 | goto error_put_reg_pos; | ||
367 | |||
368 | pos_voltage_uv = regulator_get_voltage(st->reg_vdd); | ||
369 | } | ||
370 | |||
371 | st->reg_vss = regulator_get(&spi->dev, "vss"); | ||
372 | if (!IS_ERR(st->reg_vss)) { | ||
373 | ret = regulator_enable(st->reg_vss); | ||
374 | if (ret) | ||
375 | goto error_put_reg_neg; | ||
376 | |||
377 | neg_voltage_uv = regulator_get_voltage(st->reg_vss); | ||
378 | } | ||
379 | |||
380 | st->pwr_down = true; | ||
381 | st->spi = spi; | ||
382 | |||
383 | if (!IS_ERR(st->reg_vss) && !IS_ERR(st->reg_vdd)) { | ||
384 | st->vref_mv = (pos_voltage_uv + neg_voltage_uv) / 1000; | ||
385 | st->vref_neg_mv = neg_voltage_uv / 1000; | ||
386 | } else if (pdata) { | ||
387 | st->vref_mv = pdata->vref_pos_mv + pdata->vref_neg_mv; | ||
388 | st->vref_neg_mv = pdata->vref_neg_mv; | ||
389 | } else { | ||
390 | dev_warn(&spi->dev, "reference voltage unspecified\n"); | ||
391 | } | ||
392 | |||
393 | ret = ad5791_spi_write(spi, AD5791_ADDR_SW_CTRL, AD5791_SWCTRL_RESET); | ||
394 | if (ret) | ||
395 | goto error_disable_reg_neg; | ||
396 | |||
397 | st->chip_info = &ad5791_chip_info_tbl[spi_get_device_id(spi) | ||
398 | ->driver_data]; | ||
399 | |||
400 | |||
401 | st->ctrl = AD5761_CTRL_LINCOMP(st->chip_info->get_lin_comp(st->vref_mv)) | ||
402 | | ((pdata && pdata->use_rbuf_gain2) ? 0 : AD5791_CTRL_RBUF) | | ||
403 | AD5791_CTRL_BIN2SC; | ||
404 | |||
405 | ret = ad5791_spi_write(spi, AD5791_ADDR_CTRL, st->ctrl | | ||
406 | AD5791_CTRL_OPGND | AD5791_CTRL_DACTRI); | ||
407 | if (ret) | ||
408 | goto error_disable_reg_neg; | ||
409 | |||
410 | spi_set_drvdata(spi, indio_dev); | ||
411 | indio_dev->dev.parent = &spi->dev; | ||
412 | indio_dev->info = &ad5791_info; | ||
413 | indio_dev->modes = INDIO_DIRECT_MODE; | ||
414 | indio_dev->channels | ||
415 | = &ad5791_channels[spi_get_device_id(spi)->driver_data]; | ||
416 | indio_dev->num_channels = 1; | ||
417 | indio_dev->name = spi_get_device_id(st->spi)->name; | ||
418 | ret = iio_device_register(indio_dev); | ||
419 | if (ret) | ||
420 | goto error_disable_reg_neg; | ||
421 | |||
422 | return 0; | ||
423 | |||
424 | error_disable_reg_neg: | ||
425 | if (!IS_ERR(st->reg_vss)) | ||
426 | regulator_disable(st->reg_vss); | ||
427 | error_put_reg_neg: | ||
428 | if (!IS_ERR(st->reg_vss)) | ||
429 | regulator_put(st->reg_vss); | ||
430 | |||
431 | if (!IS_ERR(st->reg_vdd)) | ||
432 | regulator_disable(st->reg_vdd); | ||
433 | error_put_reg_pos: | ||
434 | if (!IS_ERR(st->reg_vdd)) | ||
435 | regulator_put(st->reg_vdd); | ||
436 | iio_device_free(indio_dev); | ||
437 | error_ret: | ||
438 | |||
439 | return ret; | ||
440 | } | ||
441 | |||
442 | static int __devexit ad5791_remove(struct spi_device *spi) | ||
443 | { | ||
444 | struct iio_dev *indio_dev = spi_get_drvdata(spi); | ||
445 | struct ad5791_state *st = iio_priv(indio_dev); | ||
446 | |||
447 | iio_device_unregister(indio_dev); | ||
448 | if (!IS_ERR(st->reg_vdd)) { | ||
449 | regulator_disable(st->reg_vdd); | ||
450 | regulator_put(st->reg_vdd); | ||
451 | } | ||
452 | |||
453 | if (!IS_ERR(st->reg_vss)) { | ||
454 | regulator_disable(st->reg_vss); | ||
455 | regulator_put(st->reg_vss); | ||
456 | } | ||
457 | iio_device_free(indio_dev); | ||
458 | |||
459 | return 0; | ||
460 | } | ||
461 | |||
462 | static const struct spi_device_id ad5791_id[] = { | ||
463 | {"ad5760", ID_AD5760}, | ||
464 | {"ad5780", ID_AD5780}, | ||
465 | {"ad5781", ID_AD5781}, | ||
466 | {"ad5790", ID_AD5791}, | ||
467 | {"ad5791", ID_AD5791}, | ||
468 | {} | ||
469 | }; | ||
470 | MODULE_DEVICE_TABLE(spi, ad5791_id); | ||
471 | |||
472 | static struct spi_driver ad5791_driver = { | ||
473 | .driver = { | ||
474 | .name = "ad5791", | ||
475 | .owner = THIS_MODULE, | ||
476 | }, | ||
477 | .probe = ad5791_probe, | ||
478 | .remove = __devexit_p(ad5791_remove), | ||
479 | .id_table = ad5791_id, | ||
480 | }; | ||
481 | module_spi_driver(ad5791_driver); | ||
482 | |||
483 | MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); | ||
484 | MODULE_DESCRIPTION("Analog Devices AD5760/AD5780/AD5781/AD5790/AD5791 DAC"); | ||
485 | MODULE_LICENSE("GPL v2"); | ||