]> Git Repo - linux.git/blame - drivers/staging/iio/dac/ad5791.c
Staging: comedi: fix initialise statics to 0 or NULL issue in cb_das16_cs.c
[linux.git] / drivers / staging / iio / dac / ad5791.c
CommitLineData
69d900a6 1/*
ba1c2bb2 2 * AD5760, AD5780, AD5781, AD5791 Voltage Output Digital to Analog Converter
69d900a6
MH
3 *
4 * Copyright 2011 Analog Devices Inc.
5 *
6 * Licensed under the GPL-2.
7 */
8
9#include <linux/interrupt.h>
69d900a6
MH
10#include <linux/fs.h>
11#include <linux/device.h>
12#include <linux/kernel.h>
13#include <linux/spi/spi.h>
14#include <linux/slab.h>
15#include <linux/sysfs.h>
16#include <linux/regulator/consumer.h>
99c97852 17#include <linux/module.h>
69d900a6
MH
18
19#include "../iio.h"
20#include "../sysfs.h"
21#include "dac.h"
22#include "ad5791.h"
23
24static int ad5791_spi_write(struct spi_device *spi, u8 addr, u32 val)
25{
26 union {
27 u32 d32;
28 u8 d8[4];
29 } data;
30
31 data.d32 = cpu_to_be32(AD5791_CMD_WRITE |
32 AD5791_ADDR(addr) |
33 (val & AD5791_DAC_MASK));
34
35 return spi_write(spi, &data.d8[1], 3);
36}
37
38static int ad5791_spi_read(struct spi_device *spi, u8 addr, u32 *val)
39{
40 union {
41 u32 d32;
42 u8 d8[4];
43 } data[3];
44 int ret;
45 struct spi_message msg;
46 struct spi_transfer xfers[] = {
47 {
48 .tx_buf = &data[0].d8[1],
49 .bits_per_word = 8,
50 .len = 3,
51 .cs_change = 1,
52 }, {
53 .tx_buf = &data[1].d8[1],
54 .rx_buf = &data[2].d8[1],
55 .bits_per_word = 8,
56 .len = 3,
57 },
58 };
59
60 data[0].d32 = cpu_to_be32(AD5791_CMD_READ |
61 AD5791_ADDR(addr));
62 data[1].d32 = cpu_to_be32(AD5791_ADDR(AD5791_ADDR_NOOP));
63
64 spi_message_init(&msg);
65 spi_message_add_tail(&xfers[0], &msg);
66 spi_message_add_tail(&xfers[1], &msg);
67 ret = spi_sync(spi, &msg);
68
69 *val = be32_to_cpu(data[2].d32);
70
71 return ret;
72}
73
c5b99396
JC
74#define AD5791_CHAN(bits, shift) { \
75 .type = IIO_VOLTAGE, \
76 .output = 1, \
77 .indexed = 1, \
78 .address = AD5791_ADDR_DAC0, \
79 .channel = 0, \
c8a9f805
JC
80 .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT | \
81 IIO_CHAN_INFO_OFFSET_SHARED_BIT, \
c5b99396 82 .scan_type = IIO_ST('u', bits, 24, shift) \
69d900a6
MH
83}
84
c5b99396
JC
85static const struct iio_chan_spec ad5791_channels[] = {
86 [ID_AD5760] = AD5791_CHAN(16, 4),
87 [ID_AD5780] = AD5791_CHAN(18, 2),
88 [ID_AD5781] = AD5791_CHAN(18, 2),
89 [ID_AD5791] = AD5791_CHAN(20, 0)
90};
69d900a6
MH
91
92static ssize_t ad5791_read_powerdown_mode(struct device *dev,
93 struct device_attribute *attr, char *buf)
94{
95 struct iio_dev *indio_dev = dev_get_drvdata(dev);
f5730d52 96 struct ad5791_state *st = iio_priv(indio_dev);
69d900a6
MH
97
98 const char mode[][14] = {"6kohm_to_gnd", "three_state"};
99
100 return sprintf(buf, "%s\n", mode[st->pwr_down_mode]);
101}
102
103static ssize_t ad5791_write_powerdown_mode(struct device *dev,
104 struct device_attribute *attr,
105 const char *buf, size_t len)
106{
107 struct iio_dev *indio_dev = dev_get_drvdata(dev);
f5730d52 108 struct ad5791_state *st = iio_priv(indio_dev);
69d900a6
MH
109 int ret;
110
111 if (sysfs_streq(buf, "6kohm_to_gnd"))
112 st->pwr_down_mode = AD5791_DAC_PWRDN_6K;
113 else if (sysfs_streq(buf, "three_state"))
114 st->pwr_down_mode = AD5791_DAC_PWRDN_3STATE;
115 else
116 ret = -EINVAL;
117
118 return ret ? ret : len;
119}
120
121static ssize_t ad5791_read_dac_powerdown(struct device *dev,
122 struct device_attribute *attr,
123 char *buf)
124{
125 struct iio_dev *indio_dev = dev_get_drvdata(dev);
f5730d52 126 struct ad5791_state *st = iio_priv(indio_dev);
69d900a6
MH
127
128 return sprintf(buf, "%d\n", st->pwr_down);
129}
130
131static ssize_t ad5791_write_dac_powerdown(struct device *dev,
132 struct device_attribute *attr,
133 const char *buf, size_t len)
134{
135 long readin;
136 int ret;
137 struct iio_dev *indio_dev = dev_get_drvdata(dev);
f5730d52 138 struct ad5791_state *st = iio_priv(indio_dev);
69d900a6
MH
139
140 ret = strict_strtol(buf, 10, &readin);
141 if (ret)
142 return ret;
143
144 if (readin == 0) {
145 st->pwr_down = false;
146 st->ctrl &= ~(AD5791_CTRL_OPGND | AD5791_CTRL_DACTRI);
147 } else if (readin == 1) {
148 st->pwr_down = true;
149 if (st->pwr_down_mode == AD5791_DAC_PWRDN_6K)
150 st->ctrl |= AD5791_CTRL_OPGND;
151 else if (st->pwr_down_mode == AD5791_DAC_PWRDN_3STATE)
152 st->ctrl |= AD5791_CTRL_DACTRI;
153 } else
154 ret = -EINVAL;
155
156 ret = ad5791_spi_write(st->spi, AD5791_ADDR_CTRL, st->ctrl);
157
158 return ret ? ret : len;
159}
160
f1a61a88 161static IIO_DEVICE_ATTR(out_voltage_powerdown_mode, S_IRUGO |
69d900a6
MH
162 S_IWUSR, ad5791_read_powerdown_mode,
163 ad5791_write_powerdown_mode, 0);
164
f1a61a88 165static IIO_CONST_ATTR(out_voltage_powerdown_mode_available,
69d900a6
MH
166 "6kohm_to_gnd three_state");
167
168#define IIO_DEV_ATTR_DAC_POWERDOWN(_num, _show, _store, _addr) \
f1a61a88 169 IIO_DEVICE_ATTR(out_voltage##_num##_powerdown, \
69d900a6
MH
170 S_IRUGO | S_IWUSR, _show, _store, _addr)
171
172static IIO_DEV_ATTR_DAC_POWERDOWN(0, ad5791_read_dac_powerdown,
173 ad5791_write_dac_powerdown, 0);
174
175static struct attribute *ad5791_attributes[] = {
f1a61a88
LPC
176 &iio_dev_attr_out_voltage0_powerdown.dev_attr.attr,
177 &iio_dev_attr_out_voltage_powerdown_mode.dev_attr.attr,
178 &iio_const_attr_out_voltage_powerdown_mode_available.dev_attr.attr,
69d900a6
MH
179 NULL,
180};
181
182static const struct attribute_group ad5791_attribute_group = {
183 .attrs = ad5791_attributes,
184};
185
69d900a6
MH
186static int ad5791_get_lin_comp(unsigned int span)
187{
188 if (span <= 10000)
189 return AD5791_LINCOMP_0_10;
190 else if (span <= 12000)
191 return AD5791_LINCOMP_10_12;
192 else if (span <= 16000)
193 return AD5791_LINCOMP_12_16;
194 else if (span <= 19000)
195 return AD5791_LINCOMP_16_19;
196 else
197 return AD5791_LINCOMP_19_20;
198}
199
ba1c2bb2
MH
200static int ad5780_get_lin_comp(unsigned int span)
201{
202 if (span <= 10000)
203 return AD5780_LINCOMP_0_10;
204 else
205 return AD5780_LINCOMP_10_20;
206}
ba1c2bb2
MH
207static const struct ad5791_chip_info ad5791_chip_info_tbl[] = {
208 [ID_AD5760] = {
ba1c2bb2
MH
209 .get_lin_comp = ad5780_get_lin_comp,
210 },
211 [ID_AD5780] = {
ba1c2bb2
MH
212 .get_lin_comp = ad5780_get_lin_comp,
213 },
214 [ID_AD5781] = {
ba1c2bb2
MH
215 .get_lin_comp = ad5791_get_lin_comp,
216 },
217 [ID_AD5791] = {
ba1c2bb2
MH
218 .get_lin_comp = ad5791_get_lin_comp,
219 },
220};
221
c5b99396
JC
222static int ad5791_read_raw(struct iio_dev *indio_dev,
223 struct iio_chan_spec const *chan,
224 int *val,
225 int *val2,
226 long m)
227{
228 struct ad5791_state *st = iio_priv(indio_dev);
9dc9961d 229 u64 val64;
c5b99396
JC
230 int ret;
231
232 switch (m) {
233 case 0:
234 ret = ad5791_spi_read(st->spi, chan->address, val);
235 if (ret)
236 return ret;
237 *val &= AD5791_DAC_MASK;
238 *val >>= chan->scan_type.shift;
c5b99396 239 return IIO_VAL_INT;
c8a9f805 240 case IIO_CHAN_INFO_SCALE:
c5b99396 241 *val = 0;
75bb23a2 242 *val2 = (((u64)st->vref_mv) * 1000000ULL) >> chan->scan_type.realbits;
c5b99396 243 return IIO_VAL_INT_PLUS_MICRO;
c8a9f805 244 case IIO_CHAN_INFO_OFFSET:
9dc9961d
LPC
245 val64 = (((u64)st->vref_neg_mv) << chan->scan_type.realbits);
246 do_div(val64, st->vref_mv);
247 *val = -val64;
248 return IIO_VAL_INT;
c5b99396
JC
249 default:
250 return -EINVAL;
251 }
252
253};
254
255
256static int ad5791_write_raw(struct iio_dev *indio_dev,
257 struct iio_chan_spec const *chan,
258 int val,
259 int val2,
260 long mask)
261{
262 struct ad5791_state *st = iio_priv(indio_dev);
263
264 switch (mask) {
265 case 0:
021c0a38 266 val &= AD5791_RES_MASK(chan->scan_type.realbits);
c5b99396
JC
267 val <<= chan->scan_type.shift;
268
269 return ad5791_spi_write(st->spi, chan->address, val);
270
271 default:
272 return -EINVAL;
273 }
274}
275
6fe8135f 276static const struct iio_info ad5791_info = {
c5b99396
JC
277 .read_raw = &ad5791_read_raw,
278 .write_raw = &ad5791_write_raw,
6fe8135f
JC
279 .attrs = &ad5791_attribute_group,
280 .driver_module = THIS_MODULE,
281};
282
69d900a6
MH
283static int __devinit ad5791_probe(struct spi_device *spi)
284{
285 struct ad5791_platform_data *pdata = spi->dev.platform_data;
f5730d52 286 struct iio_dev *indio_dev;
69d900a6
MH
287 struct ad5791_state *st;
288 int ret, pos_voltage_uv = 0, neg_voltage_uv = 0;
289
26a54797
JC
290 indio_dev = iio_allocate_device(sizeof(*st));
291 if (indio_dev == NULL) {
292 ret = -ENOMEM;
293 goto error_ret;
294 }
295 st = iio_priv(indio_dev);
296 st->reg_vdd = regulator_get(&spi->dev, "vdd");
297 if (!IS_ERR(st->reg_vdd)) {
298 ret = regulator_enable(st->reg_vdd);
69d900a6
MH
299 if (ret)
300 goto error_put_reg_pos;
301
26a54797 302 pos_voltage_uv = regulator_get_voltage(st->reg_vdd);
69d900a6
MH
303 }
304
26a54797
JC
305 st->reg_vss = regulator_get(&spi->dev, "vss");
306 if (!IS_ERR(st->reg_vss)) {
307 ret = regulator_enable(st->reg_vss);
69d900a6
MH
308 if (ret)
309 goto error_put_reg_neg;
310
26a54797 311 neg_voltage_uv = regulator_get_voltage(st->reg_vss);
69d900a6
MH
312 }
313
f5730d52
JC
314 st->pwr_down = true;
315 st->spi = spi;
316
9dc9961d
LPC
317 if (!IS_ERR(st->reg_vss) && !IS_ERR(st->reg_vdd)) {
318 st->vref_mv = (pos_voltage_uv + neg_voltage_uv) / 1000;
319 st->vref_neg_mv = neg_voltage_uv / 1000;
320 } else if (pdata) {
321 st->vref_mv = pdata->vref_pos_mv + pdata->vref_neg_mv;
322 st->vref_neg_mv = pdata->vref_neg_mv;
323 } else {
69d900a6 324 dev_warn(&spi->dev, "reference voltage unspecified\n");
9dc9961d 325 }
69d900a6
MH
326
327 ret = ad5791_spi_write(spi, AD5791_ADDR_SW_CTRL, AD5791_SWCTRL_RESET);
328 if (ret)
26a54797 329 goto error_disable_reg_neg;
69d900a6 330
c5b99396
JC
331 st->chip_info = &ad5791_chip_info_tbl[spi_get_device_id(spi)
332 ->driver_data];
69d900a6
MH
333
334
ba1c2bb2
MH
335 st->ctrl = AD5761_CTRL_LINCOMP(st->chip_info->get_lin_comp(st->vref_mv))
336 | ((pdata && pdata->use_rbuf_gain2) ? 0 : AD5791_CTRL_RBUF) |
69d900a6
MH
337 AD5791_CTRL_BIN2SC;
338
339 ret = ad5791_spi_write(spi, AD5791_ADDR_CTRL, st->ctrl |
340 AD5791_CTRL_OPGND | AD5791_CTRL_DACTRI);
341 if (ret)
26a54797 342 goto error_disable_reg_neg;
69d900a6 343
f5730d52
JC
344 spi_set_drvdata(spi, indio_dev);
345 indio_dev->dev.parent = &spi->dev;
346 indio_dev->info = &ad5791_info;
347 indio_dev->modes = INDIO_DIRECT_MODE;
c5b99396
JC
348 indio_dev->channels
349 = &ad5791_channels[spi_get_device_id(spi)->driver_data];
350 indio_dev->num_channels = 1;
351 indio_dev->name = spi_get_device_id(st->spi)->name;
f5730d52 352 ret = iio_device_register(indio_dev);
69d900a6 353 if (ret)
26a54797 354 goto error_disable_reg_neg;
69d900a6
MH
355
356 return 0;
357
69d900a6 358error_disable_reg_neg:
26a54797
JC
359 if (!IS_ERR(st->reg_vss))
360 regulator_disable(st->reg_vss);
69d900a6 361error_put_reg_neg:
26a54797
JC
362 if (!IS_ERR(st->reg_vss))
363 regulator_put(st->reg_vss);
69d900a6 364
26a54797
JC
365 if (!IS_ERR(st->reg_vdd))
366 regulator_disable(st->reg_vdd);
69d900a6 367error_put_reg_pos:
26a54797
JC
368 if (!IS_ERR(st->reg_vdd))
369 regulator_put(st->reg_vdd);
370 iio_free_device(indio_dev);
371error_ret:
69d900a6 372
69d900a6
MH
373 return ret;
374}
375
376static int __devexit ad5791_remove(struct spi_device *spi)
377{
f5730d52
JC
378 struct iio_dev *indio_dev = spi_get_drvdata(spi);
379 struct ad5791_state *st = iio_priv(indio_dev);
69d900a6 380
d2fffd6c 381 iio_device_unregister(indio_dev);
69d900a6 382 if (!IS_ERR(st->reg_vdd)) {
26a54797
JC
383 regulator_disable(st->reg_vdd);
384 regulator_put(st->reg_vdd);
69d900a6
MH
385 }
386
387 if (!IS_ERR(st->reg_vss)) {
26a54797
JC
388 regulator_disable(st->reg_vss);
389 regulator_put(st->reg_vss);
69d900a6 390 }
d2fffd6c 391 iio_free_device(indio_dev);
26d25ae3 392
69d900a6
MH
393 return 0;
394}
395
396static const struct spi_device_id ad5791_id[] = {
ba1c2bb2
MH
397 {"ad5760", ID_AD5760},
398 {"ad5780", ID_AD5780},
69d900a6 399 {"ad5781", ID_AD5781},
ba1c2bb2 400 {"ad5791", ID_AD5791},
69d900a6
MH
401 {}
402};
55e4390c 403MODULE_DEVICE_TABLE(spi, ad5791_id);
69d900a6
MH
404
405static struct spi_driver ad5791_driver = {
406 .driver = {
407 .name = "ad5791",
408 .owner = THIS_MODULE,
409 },
410 .probe = ad5791_probe,
411 .remove = __devexit_p(ad5791_remove),
412 .id_table = ad5791_id,
413};
414
415static __init int ad5791_spi_init(void)
416{
417 return spi_register_driver(&ad5791_driver);
418}
419module_init(ad5791_spi_init);
420
421static __exit void ad5791_spi_exit(void)
422{
423 spi_unregister_driver(&ad5791_driver);
424}
425module_exit(ad5791_spi_exit);
426
427MODULE_AUTHOR("Michael Hennerich <[email protected]>");
ba1c2bb2 428MODULE_DESCRIPTION("Analog Devices AD5760/AD5780/AD5781/AD5791 DAC");
69d900a6 429MODULE_LICENSE("GPL v2");
This page took 0.266141 seconds and 4 git commands to generate.