diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-22 10:38:37 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-22 10:38:37 -0500 |
commit | fcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (patch) | |
tree | a57612d1888735a2ec7972891b68c1ac5ec8faea /drivers/staging/iio/dac | |
parent | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff) |
Diffstat (limited to 'drivers/staging/iio/dac')
-rw-r--r-- | drivers/staging/iio/dac/Kconfig | 64 | ||||
-rw-r--r-- | drivers/staging/iio/dac/Makefile | 10 | ||||
-rw-r--r-- | drivers/staging/iio/dac/ad5446.c | 480 | ||||
-rw-r--r-- | drivers/staging/iio/dac/ad5446.h | 109 | ||||
-rw-r--r-- | drivers/staging/iio/dac/ad5504.c | 397 | ||||
-rw-r--r-- | drivers/staging/iio/dac/ad5504.h | 68 | ||||
-rw-r--r-- | drivers/staging/iio/dac/ad5624r.h | 79 | ||||
-rw-r--r-- | drivers/staging/iio/dac/ad5624r_spi.c | 336 | ||||
-rw-r--r-- | drivers/staging/iio/dac/ad5686.c | 497 | ||||
-rw-r--r-- | drivers/staging/iio/dac/ad5791.c | 442 | ||||
-rw-r--r-- | drivers/staging/iio/dac/ad5791.h | 114 | ||||
-rw-r--r-- | drivers/staging/iio/dac/dac.h | 6 | ||||
-rw-r--r-- | drivers/staging/iio/dac/max517.c | 295 | ||||
-rw-r--r-- | drivers/staging/iio/dac/max517.h | 19 |
14 files changed, 2916 insertions, 0 deletions
diff --git a/drivers/staging/iio/dac/Kconfig b/drivers/staging/iio/dac/Kconfig new file mode 100644 index 00000000000..7ddae357f20 --- /dev/null +++ b/drivers/staging/iio/dac/Kconfig | |||
@@ -0,0 +1,64 @@ | |||
1 | # | ||
2 | # DAC drivers | ||
3 | # | ||
4 | comment "Digital to analog convertors" | ||
5 | |||
6 | config AD5624R_SPI | ||
7 | tristate "Analog Devices AD5624/44/64R DAC spi driver" | ||
8 | depends on SPI | ||
9 | help | ||
10 | Say yes here to build support for Analog Devices AD5624R, AD5644R and | ||
11 | AD5664R convertors (DAC). This driver uses the common SPI interface. | ||
12 | |||
13 | config AD5446 | ||
14 | tristate "Analog Devices AD5444/6, AD5620/40/60 and AD5542A/12A DAC SPI driver" | ||
15 | depends on SPI | ||
16 | help | ||
17 | Say yes here to build support for Analog Devices AD5444, AD5446, | ||
18 | AD5512A, AD5542A, AD5543, AD5553, AD5601, AD5611, AD5620, AD5621, | ||
19 | AD5640, AD5660 DACs. | ||
20 | |||
21 | To compile this driver as a module, choose M here: the | ||
22 | module will be called ad5446. | ||
23 | |||
24 | config AD5504 | ||
25 | tristate "Analog Devices AD5504/AD5501 DAC SPI driver" | ||
26 | depends on SPI | ||
27 | help | ||
28 | Say yes here to build support for Analog Devices AD5504, AD5501, | ||
29 | High Voltage Digital to Analog Converter. | ||
30 | |||
31 | To compile this driver as a module, choose M here: the | ||
32 | module will be called ad5504. | ||
33 | |||
34 | config AD5791 | ||
35 | tristate "Analog Devices AD5760/AD5780/AD5781/AD5791 DAC SPI driver" | ||
36 | depends on SPI | ||
37 | help | ||
38 | Say yes here to build support for Analog Devices AD5760, AD5780, | ||
39 | AD5781, AD5791 High Resolution Voltage Output Digital to | ||
40 | Analog Converter. | ||
41 | |||
42 | To compile this driver as a module, choose M here: the | ||
43 | module will be called ad5791. | ||
44 | |||
45 | config AD5686 | ||
46 | tristate "Analog Devices AD5686R/AD5685R/AD5684R DAC SPI driver" | ||
47 | depends on SPI | ||
48 | help | ||
49 | Say yes here to build support for Analog Devices AD5686R, AD5685R, | ||
50 | AD5684R, AD5791 Voltage Output Digital to | ||
51 | Analog Converter. | ||
52 | |||
53 | To compile this driver as a module, choose M here: the | ||
54 | module will be called ad5686. | ||
55 | |||
56 | config MAX517 | ||
57 | tristate "Maxim MAX517/518/519 DAC driver" | ||
58 | depends on I2C && EXPERIMENTAL | ||
59 | help | ||
60 | If you say yes here you get support for the Maxim chips MAX517, | ||
61 | MAX518 and MAX519 (I2C 8-Bit DACs with rail-to-rail outputs). | ||
62 | |||
63 | This driver can also be built as a module. If so, the module | ||
64 | will be called max517. | ||
diff --git a/drivers/staging/iio/dac/Makefile b/drivers/staging/iio/dac/Makefile new file mode 100644 index 00000000000..7f4f2ed031e --- /dev/null +++ b/drivers/staging/iio/dac/Makefile | |||
@@ -0,0 +1,10 @@ | |||
1 | # | ||
2 | # Makefile for industrial I/O DAC drivers | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_AD5624R_SPI) += ad5624r_spi.o | ||
6 | obj-$(CONFIG_AD5504) += ad5504.o | ||
7 | obj-$(CONFIG_AD5446) += ad5446.o | ||
8 | obj-$(CONFIG_AD5791) += ad5791.o | ||
9 | obj-$(CONFIG_AD5686) += ad5686.o | ||
10 | obj-$(CONFIG_MAX517) += max517.o | ||
diff --git a/drivers/staging/iio/dac/ad5446.c b/drivers/staging/iio/dac/ad5446.c new file mode 100644 index 00000000000..e8a9d0bf1ed --- /dev/null +++ b/drivers/staging/iio/dac/ad5446.c | |||
@@ -0,0 +1,480 @@ | |||
1 | /* | ||
2 | * AD5446 SPI DAC driver | ||
3 | * | ||
4 | * Copyright 2010 Analog Devices Inc. | ||
5 | * | ||
6 | * Licensed under the GPL-2 or later. | ||
7 | */ | ||
8 | |||
9 | #include <linux/interrupt.h> | ||
10 | #include <linux/workqueue.h> | ||
11 | #include <linux/device.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/slab.h> | ||
14 | #include <linux/sysfs.h> | ||
15 | #include <linux/list.h> | ||
16 | #include <linux/spi/spi.h> | ||
17 | #include <linux/regulator/consumer.h> | ||
18 | #include <linux/err.h> | ||
19 | |||
20 | #include "../iio.h" | ||
21 | #include "../sysfs.h" | ||
22 | #include "dac.h" | ||
23 | |||
24 | #include "ad5446.h" | ||
25 | |||
26 | static void ad5446_store_sample(struct ad5446_state *st, unsigned val) | ||
27 | { | ||
28 | st->data.d16 = cpu_to_be16(AD5446_LOAD | | ||
29 | (val << st->chip_info->left_shift)); | ||
30 | } | ||
31 | |||
32 | static void ad5542_store_sample(struct ad5446_state *st, unsigned val) | ||
33 | { | ||
34 | st->data.d16 = cpu_to_be16(val << st->chip_info->left_shift); | ||
35 | } | ||
36 | |||
37 | static void ad5620_store_sample(struct ad5446_state *st, unsigned val) | ||
38 | { | ||
39 | st->data.d16 = cpu_to_be16(AD5620_LOAD | | ||
40 | (val << st->chip_info->left_shift)); | ||
41 | } | ||
42 | |||
43 | static void ad5660_store_sample(struct ad5446_state *st, unsigned val) | ||
44 | { | ||
45 | val |= AD5660_LOAD; | ||
46 | st->data.d24[0] = (val >> 16) & 0xFF; | ||
47 | st->data.d24[1] = (val >> 8) & 0xFF; | ||
48 | st->data.d24[2] = val & 0xFF; | ||
49 | } | ||
50 | |||
51 | static void ad5620_store_pwr_down(struct ad5446_state *st, unsigned mode) | ||
52 | { | ||
53 | st->data.d16 = cpu_to_be16(mode << 14); | ||
54 | } | ||
55 | |||
56 | static void ad5660_store_pwr_down(struct ad5446_state *st, unsigned mode) | ||
57 | { | ||
58 | unsigned val = mode << 16; | ||
59 | |||
60 | st->data.d24[0] = (val >> 16) & 0xFF; | ||
61 | st->data.d24[1] = (val >> 8) & 0xFF; | ||
62 | st->data.d24[2] = val & 0xFF; | ||
63 | } | ||
64 | |||
65 | static ssize_t ad5446_write(struct device *dev, | ||
66 | struct device_attribute *attr, | ||
67 | const char *buf, | ||
68 | size_t len) | ||
69 | { | ||
70 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
71 | struct ad5446_state *st = iio_priv(dev_info); | ||
72 | int ret; | ||
73 | long val; | ||
74 | |||
75 | ret = strict_strtol(buf, 10, &val); | ||
76 | if (ret) | ||
77 | goto error_ret; | ||
78 | |||
79 | if (val > RES_MASK(st->chip_info->bits)) { | ||
80 | ret = -EINVAL; | ||
81 | goto error_ret; | ||
82 | } | ||
83 | |||
84 | mutex_lock(&dev_info->mlock); | ||
85 | st->cached_val = val; | ||
86 | st->chip_info->store_sample(st, val); | ||
87 | ret = spi_sync(st->spi, &st->msg); | ||
88 | mutex_unlock(&dev_info->mlock); | ||
89 | |||
90 | error_ret: | ||
91 | return ret ? ret : len; | ||
92 | } | ||
93 | |||
94 | static IIO_DEV_ATTR_OUT_RAW(0, ad5446_write, 0); | ||
95 | |||
96 | static ssize_t ad5446_show_scale(struct device *dev, | ||
97 | struct device_attribute *attr, | ||
98 | char *buf) | ||
99 | { | ||
100 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
101 | struct ad5446_state *st = iio_priv(dev_info); | ||
102 | /* Corresponds to Vref / 2^(bits) */ | ||
103 | unsigned int scale_uv = (st->vref_mv * 1000) >> st->chip_info->bits; | ||
104 | |||
105 | return sprintf(buf, "%d.%03d\n", scale_uv / 1000, scale_uv % 1000); | ||
106 | } | ||
107 | static IIO_DEVICE_ATTR(out_scale, S_IRUGO, ad5446_show_scale, NULL, 0); | ||
108 | |||
109 | static ssize_t ad5446_write_powerdown_mode(struct device *dev, | ||
110 | struct device_attribute *attr, | ||
111 | const char *buf, size_t len) | ||
112 | { | ||
113 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
114 | struct ad5446_state *st = iio_priv(dev_info); | ||
115 | |||
116 | if (sysfs_streq(buf, "1kohm_to_gnd")) | ||
117 | st->pwr_down_mode = MODE_PWRDWN_1k; | ||
118 | else if (sysfs_streq(buf, "100kohm_to_gnd")) | ||
119 | st->pwr_down_mode = MODE_PWRDWN_100k; | ||
120 | else if (sysfs_streq(buf, "three_state")) | ||
121 | st->pwr_down_mode = MODE_PWRDWN_TRISTATE; | ||
122 | else | ||
123 | return -EINVAL; | ||
124 | |||
125 | return len; | ||
126 | } | ||
127 | |||
128 | static ssize_t ad5446_read_powerdown_mode(struct device *dev, | ||
129 | struct device_attribute *attr, char *buf) | ||
130 | { | ||
131 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
132 | struct ad5446_state *st = iio_priv(dev_info); | ||
133 | |||
134 | char mode[][15] = {"", "1kohm_to_gnd", "100kohm_to_gnd", "three_state"}; | ||
135 | |||
136 | return sprintf(buf, "%s\n", mode[st->pwr_down_mode]); | ||
137 | } | ||
138 | |||
139 | static ssize_t ad5446_read_dac_powerdown(struct device *dev, | ||
140 | struct device_attribute *attr, | ||
141 | char *buf) | ||
142 | { | ||
143 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
144 | struct ad5446_state *st = iio_priv(dev_info); | ||
145 | |||
146 | return sprintf(buf, "%d\n", st->pwr_down); | ||
147 | } | ||
148 | |||
149 | static ssize_t ad5446_write_dac_powerdown(struct device *dev, | ||
150 | struct device_attribute *attr, | ||
151 | const char *buf, size_t len) | ||
152 | { | ||
153 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
154 | struct ad5446_state *st = iio_priv(dev_info); | ||
155 | unsigned long readin; | ||
156 | int ret; | ||
157 | |||
158 | ret = strict_strtol(buf, 10, &readin); | ||
159 | if (ret) | ||
160 | return ret; | ||
161 | |||
162 | if (readin > 1) | ||
163 | ret = -EINVAL; | ||
164 | |||
165 | mutex_lock(&dev_info->mlock); | ||
166 | st->pwr_down = readin; | ||
167 | |||
168 | if (st->pwr_down) | ||
169 | st->chip_info->store_pwr_down(st, st->pwr_down_mode); | ||
170 | else | ||
171 | st->chip_info->store_sample(st, st->cached_val); | ||
172 | |||
173 | ret = spi_sync(st->spi, &st->msg); | ||
174 | mutex_unlock(&dev_info->mlock); | ||
175 | |||
176 | return ret ? ret : len; | ||
177 | } | ||
178 | |||
179 | static IIO_DEVICE_ATTR(out_powerdown_mode, S_IRUGO | S_IWUSR, | ||
180 | ad5446_read_powerdown_mode, | ||
181 | ad5446_write_powerdown_mode, 0); | ||
182 | |||
183 | static IIO_CONST_ATTR(out_powerdown_mode_available, | ||
184 | "1kohm_to_gnd 100kohm_to_gnd three_state"); | ||
185 | |||
186 | static IIO_DEVICE_ATTR(out0_powerdown, S_IRUGO | S_IWUSR, | ||
187 | ad5446_read_dac_powerdown, | ||
188 | ad5446_write_dac_powerdown, 0); | ||
189 | |||
190 | static struct attribute *ad5446_attributes[] = { | ||
191 | &iio_dev_attr_out0_raw.dev_attr.attr, | ||
192 | &iio_dev_attr_out_scale.dev_attr.attr, | ||
193 | &iio_dev_attr_out0_powerdown.dev_attr.attr, | ||
194 | &iio_dev_attr_out_powerdown_mode.dev_attr.attr, | ||
195 | &iio_const_attr_out_powerdown_mode_available.dev_attr.attr, | ||
196 | NULL, | ||
197 | }; | ||
198 | |||
199 | static mode_t ad5446_attr_is_visible(struct kobject *kobj, | ||
200 | struct attribute *attr, int n) | ||
201 | { | ||
202 | struct device *dev = container_of(kobj, struct device, kobj); | ||
203 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
204 | struct ad5446_state *st = iio_priv(dev_info); | ||
205 | |||
206 | mode_t mode = attr->mode; | ||
207 | |||
208 | if (!st->chip_info->store_pwr_down && | ||
209 | (attr == &iio_dev_attr_out0_powerdown.dev_attr.attr || | ||
210 | attr == &iio_dev_attr_out_powerdown_mode.dev_attr.attr || | ||
211 | attr == | ||
212 | &iio_const_attr_out_powerdown_mode_available.dev_attr.attr)) | ||
213 | mode = 0; | ||
214 | |||
215 | return mode; | ||
216 | } | ||
217 | |||
218 | static const struct attribute_group ad5446_attribute_group = { | ||
219 | .attrs = ad5446_attributes, | ||
220 | .is_visible = ad5446_attr_is_visible, | ||
221 | }; | ||
222 | |||
223 | static const struct ad5446_chip_info ad5446_chip_info_tbl[] = { | ||
224 | [ID_AD5444] = { | ||
225 | .bits = 12, | ||
226 | .storagebits = 16, | ||
227 | .left_shift = 2, | ||
228 | .store_sample = ad5446_store_sample, | ||
229 | }, | ||
230 | [ID_AD5446] = { | ||
231 | .bits = 14, | ||
232 | .storagebits = 16, | ||
233 | .left_shift = 0, | ||
234 | .store_sample = ad5446_store_sample, | ||
235 | }, | ||
236 | [ID_AD5541A] = { | ||
237 | .bits = 16, | ||
238 | .storagebits = 16, | ||
239 | .left_shift = 0, | ||
240 | .store_sample = ad5542_store_sample, | ||
241 | }, | ||
242 | [ID_AD5542A] = { | ||
243 | .bits = 16, | ||
244 | .storagebits = 16, | ||
245 | .left_shift = 0, | ||
246 | .store_sample = ad5542_store_sample, | ||
247 | }, | ||
248 | [ID_AD5543] = { | ||
249 | .bits = 16, | ||
250 | .storagebits = 16, | ||
251 | .left_shift = 0, | ||
252 | .store_sample = ad5542_store_sample, | ||
253 | }, | ||
254 | [ID_AD5512A] = { | ||
255 | .bits = 12, | ||
256 | .storagebits = 16, | ||
257 | .left_shift = 4, | ||
258 | .store_sample = ad5542_store_sample, | ||
259 | }, | ||
260 | [ID_AD5553] = { | ||
261 | .bits = 14, | ||
262 | .storagebits = 16, | ||
263 | .left_shift = 0, | ||
264 | .store_sample = ad5542_store_sample, | ||
265 | }, | ||
266 | [ID_AD5601] = { | ||
267 | .bits = 8, | ||
268 | .storagebits = 16, | ||
269 | .left_shift = 6, | ||
270 | .store_sample = ad5542_store_sample, | ||
271 | .store_pwr_down = ad5620_store_pwr_down, | ||
272 | }, | ||
273 | [ID_AD5611] = { | ||
274 | .bits = 10, | ||
275 | .storagebits = 16, | ||
276 | .left_shift = 4, | ||
277 | .store_sample = ad5542_store_sample, | ||
278 | .store_pwr_down = ad5620_store_pwr_down, | ||
279 | }, | ||
280 | [ID_AD5621] = { | ||
281 | .bits = 12, | ||
282 | .storagebits = 16, | ||
283 | .left_shift = 2, | ||
284 | .store_sample = ad5542_store_sample, | ||
285 | .store_pwr_down = ad5620_store_pwr_down, | ||
286 | }, | ||
287 | [ID_AD5620_2500] = { | ||
288 | .bits = 12, | ||
289 | .storagebits = 16, | ||
290 | .left_shift = 2, | ||
291 | .int_vref_mv = 2500, | ||
292 | .store_sample = ad5620_store_sample, | ||
293 | .store_pwr_down = ad5620_store_pwr_down, | ||
294 | }, | ||
295 | [ID_AD5620_1250] = { | ||
296 | .bits = 12, | ||
297 | .storagebits = 16, | ||
298 | .left_shift = 2, | ||
299 | .int_vref_mv = 1250, | ||
300 | .store_sample = ad5620_store_sample, | ||
301 | .store_pwr_down = ad5620_store_pwr_down, | ||
302 | }, | ||
303 | [ID_AD5640_2500] = { | ||
304 | .bits = 14, | ||
305 | .storagebits = 16, | ||
306 | .left_shift = 0, | ||
307 | .int_vref_mv = 2500, | ||
308 | .store_sample = ad5620_store_sample, | ||
309 | .store_pwr_down = ad5620_store_pwr_down, | ||
310 | }, | ||
311 | [ID_AD5640_1250] = { | ||
312 | .bits = 14, | ||
313 | .storagebits = 16, | ||
314 | .left_shift = 0, | ||
315 | .int_vref_mv = 1250, | ||
316 | .store_sample = ad5620_store_sample, | ||
317 | .store_pwr_down = ad5620_store_pwr_down, | ||
318 | }, | ||
319 | [ID_AD5660_2500] = { | ||
320 | .bits = 16, | ||
321 | .storagebits = 24, | ||
322 | .left_shift = 0, | ||
323 | .int_vref_mv = 2500, | ||
324 | .store_sample = ad5660_store_sample, | ||
325 | .store_pwr_down = ad5660_store_pwr_down, | ||
326 | }, | ||
327 | [ID_AD5660_1250] = { | ||
328 | .bits = 16, | ||
329 | .storagebits = 24, | ||
330 | .left_shift = 0, | ||
331 | .int_vref_mv = 1250, | ||
332 | .store_sample = ad5660_store_sample, | ||
333 | .store_pwr_down = ad5660_store_pwr_down, | ||
334 | }, | ||
335 | }; | ||
336 | |||
337 | static const struct iio_info ad5446_info = { | ||
338 | .attrs = &ad5446_attribute_group, | ||
339 | .driver_module = THIS_MODULE, | ||
340 | }; | ||
341 | |||
342 | static int __devinit ad5446_probe(struct spi_device *spi) | ||
343 | { | ||
344 | struct ad5446_state *st; | ||
345 | struct iio_dev *indio_dev; | ||
346 | struct regulator *reg; | ||
347 | int ret, voltage_uv = 0; | ||
348 | |||
349 | reg = regulator_get(&spi->dev, "vcc"); | ||
350 | if (!IS_ERR(reg)) { | ||
351 | ret = regulator_enable(reg); | ||
352 | if (ret) | ||
353 | goto error_put_reg; | ||
354 | |||
355 | voltage_uv = regulator_get_voltage(reg); | ||
356 | } | ||
357 | |||
358 | indio_dev = iio_allocate_device(sizeof(*st)); | ||
359 | if (indio_dev == NULL) { | ||
360 | ret = -ENOMEM; | ||
361 | goto error_disable_reg; | ||
362 | } | ||
363 | st = iio_priv(indio_dev); | ||
364 | st->chip_info = | ||
365 | &ad5446_chip_info_tbl[spi_get_device_id(spi)->driver_data]; | ||
366 | |||
367 | spi_set_drvdata(spi, indio_dev); | ||
368 | st->reg = reg; | ||
369 | st->spi = spi; | ||
370 | |||
371 | /* Estabilish that the iio_dev is a child of the spi device */ | ||
372 | indio_dev->dev.parent = &spi->dev; | ||
373 | indio_dev->name = spi_get_device_id(spi)->name; | ||
374 | indio_dev->info = &ad5446_info; | ||
375 | indio_dev->modes = INDIO_DIRECT_MODE; | ||
376 | |||
377 | /* Setup default message */ | ||
378 | |||
379 | st->xfer.tx_buf = &st->data; | ||
380 | st->xfer.len = st->chip_info->storagebits / 8; | ||
381 | |||
382 | spi_message_init(&st->msg); | ||
383 | spi_message_add_tail(&st->xfer, &st->msg); | ||
384 | |||
385 | switch (spi_get_device_id(spi)->driver_data) { | ||
386 | case ID_AD5620_2500: | ||
387 | case ID_AD5620_1250: | ||
388 | case ID_AD5640_2500: | ||
389 | case ID_AD5640_1250: | ||
390 | case ID_AD5660_2500: | ||
391 | case ID_AD5660_1250: | ||
392 | st->vref_mv = st->chip_info->int_vref_mv; | ||
393 | break; | ||
394 | default: | ||
395 | if (voltage_uv) | ||
396 | st->vref_mv = voltage_uv / 1000; | ||
397 | else | ||
398 | dev_warn(&spi->dev, | ||
399 | "reference voltage unspecified\n"); | ||
400 | } | ||
401 | |||
402 | ret = iio_device_register(indio_dev); | ||
403 | if (ret) | ||
404 | goto error_free_device; | ||
405 | |||
406 | return 0; | ||
407 | |||
408 | error_free_device: | ||
409 | iio_free_device(indio_dev); | ||
410 | error_disable_reg: | ||
411 | if (!IS_ERR(reg)) | ||
412 | regulator_disable(reg); | ||
413 | error_put_reg: | ||
414 | if (!IS_ERR(reg)) | ||
415 | regulator_put(reg); | ||
416 | |||
417 | return ret; | ||
418 | } | ||
419 | |||
420 | static int ad5446_remove(struct spi_device *spi) | ||
421 | { | ||
422 | struct iio_dev *indio_dev = spi_get_drvdata(spi); | ||
423 | struct ad5446_state *st = iio_priv(indio_dev); | ||
424 | struct regulator *reg = st->reg; | ||
425 | |||
426 | iio_device_unregister(indio_dev); | ||
427 | if (!IS_ERR(reg)) { | ||
428 | regulator_disable(reg); | ||
429 | regulator_put(reg); | ||
430 | } | ||
431 | return 0; | ||
432 | } | ||
433 | |||
434 | static const struct spi_device_id ad5446_id[] = { | ||
435 | {"ad5444", ID_AD5444}, | ||
436 | {"ad5446", ID_AD5446}, | ||
437 | {"ad5512a", ID_AD5512A}, | ||
438 | {"ad5541a", ID_AD5541A}, | ||
439 | {"ad5542a", ID_AD5542A}, | ||
440 | {"ad5543", ID_AD5543}, | ||
441 | {"ad5553", ID_AD5553}, | ||
442 | {"ad5601", ID_AD5601}, | ||
443 | {"ad5611", ID_AD5611}, | ||
444 | {"ad5621", ID_AD5621}, | ||
445 | {"ad5620-2500", ID_AD5620_2500}, /* AD5620/40/60: */ | ||
446 | {"ad5620-1250", ID_AD5620_1250}, /* part numbers may look differently */ | ||
447 | {"ad5640-2500", ID_AD5640_2500}, | ||
448 | {"ad5640-1250", ID_AD5640_1250}, | ||
449 | {"ad5660-2500", ID_AD5660_2500}, | ||
450 | {"ad5660-1250", ID_AD5660_1250}, | ||
451 | {} | ||
452 | }; | ||
453 | |||
454 | static struct spi_driver ad5446_driver = { | ||
455 | .driver = { | ||
456 | .name = "ad5446", | ||
457 | .bus = &spi_bus_type, | ||
458 | .owner = THIS_MODULE, | ||
459 | }, | ||
460 | .probe = ad5446_probe, | ||
461 | .remove = __devexit_p(ad5446_remove), | ||
462 | .id_table = ad5446_id, | ||
463 | }; | ||
464 | |||
465 | static int __init ad5446_init(void) | ||
466 | { | ||
467 | return spi_register_driver(&ad5446_driver); | ||
468 | } | ||
469 | module_init(ad5446_init); | ||
470 | |||
471 | static void __exit ad5446_exit(void) | ||
472 | { | ||
473 | spi_unregister_driver(&ad5446_driver); | ||
474 | } | ||
475 | module_exit(ad5446_exit); | ||
476 | |||
477 | MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); | ||
478 | MODULE_DESCRIPTION("Analog Devices AD5444/AD5446 DAC"); | ||
479 | MODULE_LICENSE("GPL v2"); | ||
480 | MODULE_ALIAS("spi:ad5446"); | ||
diff --git a/drivers/staging/iio/dac/ad5446.h b/drivers/staging/iio/dac/ad5446.h new file mode 100644 index 00000000000..7118d653ac3 --- /dev/null +++ b/drivers/staging/iio/dac/ad5446.h | |||
@@ -0,0 +1,109 @@ | |||
1 | /* | ||
2 | * AD5446 SPI DAC driver | ||
3 | * | ||
4 | * Copyright 2010 Analog Devices Inc. | ||
5 | * | ||
6 | * Licensed under the GPL-2 or later. | ||
7 | */ | ||
8 | #ifndef IIO_DAC_AD5446_H_ | ||
9 | #define IIO_DAC_AD5446_H_ | ||
10 | |||
11 | /* DAC Control Bits */ | ||
12 | |||
13 | #define AD5446_LOAD (0x0 << 14) /* Load and update */ | ||
14 | #define AD5446_SDO_DIS (0x1 << 14) /* Disable SDO */ | ||
15 | #define AD5446_NOP (0x2 << 14) /* No operation */ | ||
16 | #define AD5446_CLK_RISING (0x3 << 14) /* Clock data on rising edge */ | ||
17 | |||
18 | #define AD5620_LOAD (0x0 << 14) /* Load and update Norm Operation*/ | ||
19 | #define AD5620_PWRDWN_1k (0x1 << 14) /* Power-down: 1kOhm to GND */ | ||
20 | #define AD5620_PWRDWN_100k (0x2 << 14) /* Power-down: 100kOhm to GND */ | ||
21 | #define AD5620_PWRDWN_TRISTATE (0x3 << 14) /* Power-down: Three-state */ | ||
22 | |||
23 | #define AD5660_LOAD (0x0 << 16) /* Load and update Norm Operation*/ | ||
24 | #define AD5660_PWRDWN_1k (0x1 << 16) /* Power-down: 1kOhm to GND */ | ||
25 | #define AD5660_PWRDWN_100k (0x2 << 16) /* Power-down: 100kOhm to GND */ | ||
26 | #define AD5660_PWRDWN_TRISTATE (0x3 << 16) /* Power-down: Three-state */ | ||
27 | |||
28 | #define RES_MASK(bits) ((1 << (bits)) - 1) | ||
29 | |||
30 | #define MODE_PWRDWN_1k 0x1 | ||
31 | #define MODE_PWRDWN_100k 0x2 | ||
32 | #define MODE_PWRDWN_TRISTATE 0x3 | ||
33 | |||
34 | /** | ||
35 | * struct ad5446_state - driver instance specific data | ||
36 | * @spi: spi_device | ||
37 | * @chip_info: chip model specific constants, available modes etc | ||
38 | * @reg: supply regulator | ||
39 | * @poll_work: bottom half of polling interrupt handler | ||
40 | * @vref_mv: actual reference voltage used | ||
41 | * @xfer: default spi transfer | ||
42 | * @msg: default spi message | ||
43 | * @data: spi transmit buffer | ||
44 | */ | ||
45 | |||
46 | struct ad5446_state { | ||
47 | struct spi_device *spi; | ||
48 | const struct ad5446_chip_info *chip_info; | ||
49 | struct regulator *reg; | ||
50 | struct work_struct poll_work; | ||
51 | unsigned short vref_mv; | ||
52 | unsigned cached_val; | ||
53 | unsigned pwr_down_mode; | ||
54 | unsigned pwr_down; | ||
55 | struct spi_transfer xfer; | ||
56 | struct spi_message msg; | ||
57 | union { | ||
58 | unsigned short d16; | ||
59 | unsigned char d24[3]; | ||
60 | } data; | ||
61 | }; | ||
62 | |||
63 | /** | ||
64 | * struct ad5446_chip_info - chip specific information | ||
65 | * @bits: accuracy of the DAC in bits | ||
66 | * @storagebits: number of bits written to the DAC | ||
67 | * @left_shift: number of bits the datum must be shifted | ||
68 | * @int_vref_mv: AD5620/40/60: the internal reference voltage | ||
69 | * @store_sample: chip specific helper function to store the datum | ||
70 | * @store_sample: chip specific helper function to store the powerpown cmd | ||
71 | */ | ||
72 | |||
73 | struct ad5446_chip_info { | ||
74 | u8 bits; | ||
75 | u8 storagebits; | ||
76 | u8 left_shift; | ||
77 | u16 int_vref_mv; | ||
78 | void (*store_sample) (struct ad5446_state *st, unsigned val); | ||
79 | void (*store_pwr_down) (struct ad5446_state *st, unsigned mode); | ||
80 | }; | ||
81 | |||
82 | /** | ||
83 | * ad5446_supported_device_ids: | ||
84 | * The AD5620/40/60 parts are available in different fixed internal reference | ||
85 | * voltage options. The actual part numbers may look differently | ||
86 | * (and a bit cryptic), however this style is used to make clear which | ||
87 | * parts are supported here. | ||
88 | */ | ||
89 | |||
90 | enum ad5446_supported_device_ids { | ||
91 | ID_AD5444, | ||
92 | ID_AD5446, | ||
93 | ID_AD5541A, | ||
94 | ID_AD5542A, | ||
95 | ID_AD5543, | ||
96 | ID_AD5512A, | ||
97 | ID_AD5553, | ||
98 | ID_AD5601, | ||
99 | ID_AD5611, | ||
100 | ID_AD5621, | ||
101 | ID_AD5620_2500, | ||
102 | ID_AD5620_1250, | ||
103 | ID_AD5640_2500, | ||
104 | ID_AD5640_1250, | ||
105 | ID_AD5660_2500, | ||
106 | ID_AD5660_1250, | ||
107 | }; | ||
108 | |||
109 | #endif /* IIO_DAC_AD5446_H_ */ | ||
diff --git a/drivers/staging/iio/dac/ad5504.c b/drivers/staging/iio/dac/ad5504.c new file mode 100644 index 00000000000..1915f459868 --- /dev/null +++ b/drivers/staging/iio/dac/ad5504.c | |||
@@ -0,0 +1,397 @@ | |||
1 | /* | ||
2 | * AD5504, AD5501 High Voltage Digital to Analog Converter | ||
3 | * | ||
4 | * Copyright 2011 Analog Devices Inc. | ||
5 | * | ||
6 | * Licensed under the GPL-2. | ||
7 | */ | ||
8 | |||
9 | #include <linux/interrupt.h> | ||
10 | #include <linux/gpio.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 | |||
19 | #include "../iio.h" | ||
20 | #include "../sysfs.h" | ||
21 | #include "dac.h" | ||
22 | #include "ad5504.h" | ||
23 | |||
24 | static int ad5504_spi_write(struct spi_device *spi, u8 addr, u16 val) | ||
25 | { | ||
26 | u16 tmp = cpu_to_be16(AD5504_CMD_WRITE | | ||
27 | AD5504_ADDR(addr) | | ||
28 | (val & AD5504_RES_MASK)); | ||
29 | |||
30 | return spi_write(spi, (u8 *)&tmp, 2); | ||
31 | } | ||
32 | |||
33 | static int ad5504_spi_read(struct spi_device *spi, u8 addr, u16 *val) | ||
34 | { | ||
35 | u16 tmp = cpu_to_be16(AD5504_CMD_READ | AD5504_ADDR(addr)); | ||
36 | int ret; | ||
37 | struct spi_transfer t = { | ||
38 | .tx_buf = &tmp, | ||
39 | .rx_buf = val, | ||
40 | .len = 2, | ||
41 | }; | ||
42 | struct spi_message m; | ||
43 | |||
44 | spi_message_init(&m); | ||
45 | spi_message_add_tail(&t, &m); | ||
46 | ret = spi_sync(spi, &m); | ||
47 | |||
48 | *val = be16_to_cpu(*val) & AD5504_RES_MASK; | ||
49 | |||
50 | return ret; | ||
51 | } | ||
52 | |||
53 | static ssize_t ad5504_write_dac(struct device *dev, | ||
54 | struct device_attribute *attr, | ||
55 | const char *buf, size_t len) | ||
56 | { | ||
57 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
58 | struct ad5504_state *st = iio_priv(indio_dev); | ||
59 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | ||
60 | long readin; | ||
61 | int ret; | ||
62 | |||
63 | ret = strict_strtol(buf, 10, &readin); | ||
64 | if (ret) | ||
65 | return ret; | ||
66 | |||
67 | ret = ad5504_spi_write(st->spi, this_attr->address, readin); | ||
68 | return ret ? ret : len; | ||
69 | } | ||
70 | |||
71 | static ssize_t ad5504_read_dac(struct device *dev, | ||
72 | struct device_attribute *attr, | ||
73 | char *buf) | ||
74 | { | ||
75 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
76 | struct ad5504_state *st = iio_priv(indio_dev); | ||
77 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | ||
78 | int ret; | ||
79 | u16 val; | ||
80 | |||
81 | ret = ad5504_spi_read(st->spi, this_attr->address, &val); | ||
82 | if (ret) | ||
83 | return ret; | ||
84 | |||
85 | return sprintf(buf, "%d\n", val); | ||
86 | } | ||
87 | |||
88 | static ssize_t ad5504_read_powerdown_mode(struct device *dev, | ||
89 | struct device_attribute *attr, char *buf) | ||
90 | { | ||
91 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
92 | struct ad5504_state *st = iio_priv(indio_dev); | ||
93 | |||
94 | const char mode[][14] = {"20kohm_to_gnd", "three_state"}; | ||
95 | |||
96 | return sprintf(buf, "%s\n", mode[st->pwr_down_mode]); | ||
97 | } | ||
98 | |||
99 | static ssize_t ad5504_write_powerdown_mode(struct device *dev, | ||
100 | struct device_attribute *attr, | ||
101 | const char *buf, size_t len) | ||
102 | { | ||
103 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
104 | struct ad5504_state *st = iio_priv(indio_dev); | ||
105 | int ret; | ||
106 | |||
107 | if (sysfs_streq(buf, "20kohm_to_gnd")) | ||
108 | st->pwr_down_mode = AD5504_DAC_PWRDN_20K; | ||
109 | else if (sysfs_streq(buf, "three_state")) | ||
110 | st->pwr_down_mode = AD5504_DAC_PWRDN_3STATE; | ||
111 | else | ||
112 | ret = -EINVAL; | ||
113 | |||
114 | return ret ? ret : len; | ||
115 | } | ||
116 | |||
117 | static ssize_t ad5504_read_dac_powerdown(struct device *dev, | ||
118 | struct device_attribute *attr, | ||
119 | char *buf) | ||
120 | { | ||
121 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
122 | struct ad5504_state *st = iio_priv(indio_dev); | ||
123 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | ||
124 | |||
125 | return sprintf(buf, "%d\n", | ||
126 | !(st->pwr_down_mask & (1 << this_attr->address))); | ||
127 | } | ||
128 | |||
129 | static ssize_t ad5504_write_dac_powerdown(struct device *dev, | ||
130 | struct device_attribute *attr, | ||
131 | const char *buf, size_t len) | ||
132 | { | ||
133 | long readin; | ||
134 | int ret; | ||
135 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
136 | struct ad5504_state *st = iio_priv(indio_dev); | ||
137 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | ||
138 | |||
139 | ret = strict_strtol(buf, 10, &readin); | ||
140 | if (ret) | ||
141 | return ret; | ||
142 | |||
143 | if (readin == 0) | ||
144 | st->pwr_down_mask |= (1 << this_attr->address); | ||
145 | else if (readin == 1) | ||
146 | st->pwr_down_mask &= ~(1 << this_attr->address); | ||
147 | else | ||
148 | ret = -EINVAL; | ||
149 | |||
150 | ret = ad5504_spi_write(st->spi, AD5504_ADDR_CTRL, | ||
151 | AD5504_DAC_PWRDWN_MODE(st->pwr_down_mode) | | ||
152 | AD5504_DAC_PWR(st->pwr_down_mask)); | ||
153 | |||
154 | /* writes to the CTRL register must be followed by a NOOP */ | ||
155 | ad5504_spi_write(st->spi, AD5504_ADDR_NOOP, 0); | ||
156 | |||
157 | return ret ? ret : len; | ||
158 | } | ||
159 | |||
160 | static ssize_t ad5504_show_scale(struct device *dev, | ||
161 | struct device_attribute *attr, | ||
162 | char *buf) | ||
163 | { | ||
164 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
165 | struct ad5504_state *st = iio_priv(indio_dev); | ||
166 | /* Corresponds to Vref / 2^(bits) */ | ||
167 | unsigned int scale_uv = (st->vref_mv * 1000) >> AD5505_BITS; | ||
168 | |||
169 | return sprintf(buf, "%d.%03d\n", scale_uv / 1000, scale_uv % 1000); | ||
170 | } | ||
171 | static IIO_DEVICE_ATTR(out_scale, S_IRUGO, ad5504_show_scale, NULL, 0); | ||
172 | |||
173 | #define IIO_DEV_ATTR_OUT_RW_RAW(_num, _show, _store, _addr) \ | ||
174 | IIO_DEVICE_ATTR(out##_num##_raw, \ | ||
175 | S_IRUGO | S_IWUSR, _show, _store, _addr) | ||
176 | |||
177 | static IIO_DEV_ATTR_OUT_RW_RAW(0, ad5504_read_dac, | ||
178 | ad5504_write_dac, AD5504_ADDR_DAC0); | ||
179 | static IIO_DEV_ATTR_OUT_RW_RAW(1, ad5504_read_dac, | ||
180 | ad5504_write_dac, AD5504_ADDR_DAC1); | ||
181 | static IIO_DEV_ATTR_OUT_RW_RAW(2, ad5504_read_dac, | ||
182 | ad5504_write_dac, AD5504_ADDR_DAC2); | ||
183 | static IIO_DEV_ATTR_OUT_RW_RAW(3, ad5504_read_dac, | ||
184 | ad5504_write_dac, AD5504_ADDR_DAC3); | ||
185 | |||
186 | static IIO_DEVICE_ATTR(out_powerdown_mode, S_IRUGO | | ||
187 | S_IWUSR, ad5504_read_powerdown_mode, | ||
188 | ad5504_write_powerdown_mode, 0); | ||
189 | |||
190 | static IIO_CONST_ATTR(out_powerdown_mode_available, | ||
191 | "20kohm_to_gnd three_state"); | ||
192 | |||
193 | #define IIO_DEV_ATTR_DAC_POWERDOWN(_num, _show, _store, _addr) \ | ||
194 | IIO_DEVICE_ATTR(out##_num##_powerdown, \ | ||
195 | S_IRUGO | S_IWUSR, _show, _store, _addr) | ||
196 | |||
197 | static IIO_DEV_ATTR_DAC_POWERDOWN(0, ad5504_read_dac_powerdown, | ||
198 | ad5504_write_dac_powerdown, 0); | ||
199 | static IIO_DEV_ATTR_DAC_POWERDOWN(1, ad5504_read_dac_powerdown, | ||
200 | ad5504_write_dac_powerdown, 1); | ||
201 | static IIO_DEV_ATTR_DAC_POWERDOWN(2, ad5504_read_dac_powerdown, | ||
202 | ad5504_write_dac_powerdown, 2); | ||
203 | static IIO_DEV_ATTR_DAC_POWERDOWN(3, ad5504_read_dac_powerdown, | ||
204 | ad5504_write_dac_powerdown, 3); | ||
205 | |||
206 | static struct attribute *ad5504_attributes[] = { | ||
207 | &iio_dev_attr_out0_raw.dev_attr.attr, | ||
208 | &iio_dev_attr_out1_raw.dev_attr.attr, | ||
209 | &iio_dev_attr_out2_raw.dev_attr.attr, | ||
210 | &iio_dev_attr_out3_raw.dev_attr.attr, | ||
211 | &iio_dev_attr_out0_powerdown.dev_attr.attr, | ||
212 | &iio_dev_attr_out1_powerdown.dev_attr.attr, | ||
213 | &iio_dev_attr_out2_powerdown.dev_attr.attr, | ||
214 | &iio_dev_attr_out3_powerdown.dev_attr.attr, | ||
215 | &iio_dev_attr_out_powerdown_mode.dev_attr.attr, | ||
216 | &iio_const_attr_out_powerdown_mode_available.dev_attr.attr, | ||
217 | &iio_dev_attr_out_scale.dev_attr.attr, | ||
218 | NULL, | ||
219 | }; | ||
220 | |||
221 | static const struct attribute_group ad5504_attribute_group = { | ||
222 | .attrs = ad5504_attributes, | ||
223 | }; | ||
224 | |||
225 | static struct attribute *ad5501_attributes[] = { | ||
226 | &iio_dev_attr_out0_raw.dev_attr.attr, | ||
227 | &iio_dev_attr_out0_powerdown.dev_attr.attr, | ||
228 | &iio_dev_attr_out_powerdown_mode.dev_attr.attr, | ||
229 | &iio_const_attr_out_powerdown_mode_available.dev_attr.attr, | ||
230 | &iio_dev_attr_out_scale.dev_attr.attr, | ||
231 | NULL, | ||
232 | }; | ||
233 | |||
234 | static const struct attribute_group ad5501_attribute_group = { | ||
235 | .attrs = ad5501_attributes, | ||
236 | }; | ||
237 | |||
238 | static IIO_CONST_ATTR(temp0_thresh_rising_value, "110000"); | ||
239 | static IIO_CONST_ATTR(temp0_thresh_rising_en, "1"); | ||
240 | |||
241 | static struct attribute *ad5504_ev_attributes[] = { | ||
242 | &iio_const_attr_temp0_thresh_rising_value.dev_attr.attr, | ||
243 | &iio_const_attr_temp0_thresh_rising_en.dev_attr.attr, | ||
244 | NULL, | ||
245 | }; | ||
246 | |||
247 | static struct attribute_group ad5504_ev_attribute_group = { | ||
248 | .attrs = ad5504_ev_attributes, | ||
249 | }; | ||
250 | |||
251 | static irqreturn_t ad5504_event_handler(int irq, void *private) | ||
252 | { | ||
253 | iio_push_event(private, 0, | ||
254 | IIO_UNMOD_EVENT_CODE(IIO_EV_CLASS_TEMP, | ||
255 | 0, | ||
256 | IIO_EV_TYPE_THRESH, | ||
257 | IIO_EV_DIR_RISING), | ||
258 | iio_get_time_ns()); | ||
259 | |||
260 | return IRQ_HANDLED; | ||
261 | } | ||
262 | |||
263 | static const struct iio_info ad5504_info = { | ||
264 | .attrs = &ad5504_attribute_group, | ||
265 | .num_interrupt_lines = 1, | ||
266 | .event_attrs = &ad5504_ev_attribute_group, | ||
267 | .driver_module = THIS_MODULE, | ||
268 | }; | ||
269 | |||
270 | static const struct iio_info ad5501_info = { | ||
271 | .attrs = &ad5501_attribute_group, | ||
272 | .num_interrupt_lines = 1, | ||
273 | .event_attrs = &ad5504_ev_attribute_group, | ||
274 | .driver_module = THIS_MODULE, | ||
275 | }; | ||
276 | |||
277 | static int __devinit ad5504_probe(struct spi_device *spi) | ||
278 | { | ||
279 | struct ad5504_platform_data *pdata = spi->dev.platform_data; | ||
280 | struct iio_dev *indio_dev; | ||
281 | struct ad5504_state *st; | ||
282 | struct regulator *reg; | ||
283 | int ret, voltage_uv = 0; | ||
284 | |||
285 | reg = regulator_get(&spi->dev, "vcc"); | ||
286 | if (!IS_ERR(reg)) { | ||
287 | ret = regulator_enable(reg); | ||
288 | if (ret) | ||
289 | goto error_put_reg; | ||
290 | |||
291 | voltage_uv = regulator_get_voltage(reg); | ||
292 | } | ||
293 | |||
294 | indio_dev = iio_allocate_device(sizeof(*st)); | ||
295 | if (indio_dev == NULL) { | ||
296 | ret = -ENOMEM; | ||
297 | goto error_disable_reg; | ||
298 | } | ||
299 | spi_set_drvdata(spi, indio_dev); | ||
300 | st = iio_priv(indio_dev); | ||
301 | if (voltage_uv) | ||
302 | st->vref_mv = voltage_uv / 1000; | ||
303 | else if (pdata) | ||
304 | st->vref_mv = pdata->vref_mv; | ||
305 | else | ||
306 | dev_warn(&spi->dev, "reference voltage unspecified\n"); | ||
307 | |||
308 | st->reg = reg; | ||
309 | st->spi = spi; | ||
310 | indio_dev->dev.parent = &spi->dev; | ||
311 | indio_dev->name = spi_get_device_id(st->spi)->name; | ||
312 | if (spi_get_device_id(st->spi)->driver_data == ID_AD5501) | ||
313 | indio_dev->info = &ad5501_info; | ||
314 | else | ||
315 | indio_dev->info = &ad5504_info; | ||
316 | indio_dev->modes = INDIO_DIRECT_MODE; | ||
317 | |||
318 | ret = iio_device_register(indio_dev); | ||
319 | if (ret) | ||
320 | goto error_free_dev; | ||
321 | |||
322 | if (spi->irq) { | ||
323 | ret = request_threaded_irq(spi->irq, | ||
324 | NULL, | ||
325 | &ad5504_event_handler, | ||
326 | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, | ||
327 | spi_get_device_id(st->spi)->name, | ||
328 | indio_dev); | ||
329 | if (ret) | ||
330 | goto error_unreg_iio_device; | ||
331 | } | ||
332 | |||
333 | return 0; | ||
334 | |||
335 | error_unreg_iio_device: | ||
336 | iio_device_unregister(indio_dev); | ||
337 | error_free_dev: | ||
338 | iio_free_device(indio_dev); | ||
339 | error_disable_reg: | ||
340 | if (!IS_ERR(reg)) | ||
341 | regulator_disable(st->reg); | ||
342 | error_put_reg: | ||
343 | if (!IS_ERR(reg)) | ||
344 | regulator_put(reg); | ||
345 | |||
346 | return ret; | ||
347 | } | ||
348 | |||
349 | static int __devexit ad5504_remove(struct spi_device *spi) | ||
350 | { | ||
351 | struct iio_dev *indio_dev = spi_get_drvdata(spi); | ||
352 | struct ad5504_state *st = iio_priv(indio_dev); | ||
353 | struct regulator *reg = st->reg; | ||
354 | if (spi->irq) | ||
355 | free_irq(spi->irq, indio_dev); | ||
356 | |||
357 | iio_device_unregister(indio_dev); | ||
358 | |||
359 | if (!IS_ERR(reg)) { | ||
360 | regulator_disable(reg); | ||
361 | regulator_put(reg); | ||
362 | } | ||
363 | |||
364 | return 0; | ||
365 | } | ||
366 | |||
367 | static const struct spi_device_id ad5504_id[] = { | ||
368 | {"ad5504", ID_AD5504}, | ||
369 | {"ad5501", ID_AD5501}, | ||
370 | {} | ||
371 | }; | ||
372 | |||
373 | static struct spi_driver ad5504_driver = { | ||
374 | .driver = { | ||
375 | .name = "ad5504", | ||
376 | .owner = THIS_MODULE, | ||
377 | }, | ||
378 | .probe = ad5504_probe, | ||
379 | .remove = __devexit_p(ad5504_remove), | ||
380 | .id_table = ad5504_id, | ||
381 | }; | ||
382 | |||
383 | static __init int ad5504_spi_init(void) | ||
384 | { | ||
385 | return spi_register_driver(&ad5504_driver); | ||
386 | } | ||
387 | module_init(ad5504_spi_init); | ||
388 | |||
389 | static __exit void ad5504_spi_exit(void) | ||
390 | { | ||
391 | spi_unregister_driver(&ad5504_driver); | ||
392 | } | ||
393 | module_exit(ad5504_spi_exit); | ||
394 | |||
395 | MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); | ||
396 | MODULE_DESCRIPTION("Analog Devices AD5501/AD5501 DAC"); | ||
397 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/staging/iio/dac/ad5504.h b/drivers/staging/iio/dac/ad5504.h new file mode 100644 index 00000000000..85beb1dd29b --- /dev/null +++ b/drivers/staging/iio/dac/ad5504.h | |||
@@ -0,0 +1,68 @@ | |||
1 | /* | ||
2 | * AD5504 SPI DAC driver | ||
3 | * | ||
4 | * Copyright 2011 Analog Devices Inc. | ||
5 | * | ||
6 | * Licensed under the GPL-2. | ||
7 | */ | ||
8 | |||
9 | #ifndef SPI_AD5504_H_ | ||
10 | #define SPI_AD5504_H_ | ||
11 | |||
12 | #define AD5505_BITS 12 | ||
13 | #define AD5504_RES_MASK ((1 << (AD5505_BITS)) - 1) | ||
14 | |||
15 | #define AD5504_CMD_READ (1 << 15) | ||
16 | #define AD5504_CMD_WRITE (0 << 15) | ||
17 | #define AD5504_ADDR(addr) ((addr) << 12) | ||
18 | |||
19 | /* Registers */ | ||
20 | #define AD5504_ADDR_NOOP 0 | ||
21 | #define AD5504_ADDR_DAC0 1 | ||
22 | #define AD5504_ADDR_DAC1 2 | ||
23 | #define AD5504_ADDR_DAC2 3 | ||
24 | #define AD5504_ADDR_DAC3 4 | ||
25 | #define AD5504_ADDR_ALL_DAC 5 | ||
26 | #define AD5504_ADDR_CTRL 7 | ||
27 | |||
28 | /* Control Register */ | ||
29 | #define AD5504_DAC_PWR(ch) ((ch) << 2) | ||
30 | #define AD5504_DAC_PWRDWN_MODE(mode) ((mode) << 6) | ||
31 | #define AD5504_DAC_PWRDN_20K 0 | ||
32 | #define AD5504_DAC_PWRDN_3STATE 1 | ||
33 | |||
34 | /* | ||
35 | * TODO: struct ad5504_platform_data needs to go into include/linux/iio | ||
36 | */ | ||
37 | |||
38 | struct ad5504_platform_data { | ||
39 | u16 vref_mv; | ||
40 | }; | ||
41 | |||
42 | /** | ||
43 | * struct ad5446_state - driver instance specific data | ||
44 | * @us: spi_device | ||
45 | * @reg: supply regulator | ||
46 | * @vref_mv: actual reference voltage used | ||
47 | * @pwr_down_mask power down mask | ||
48 | * @pwr_down_mode current power down mode | ||
49 | */ | ||
50 | |||
51 | struct ad5504_state { | ||
52 | struct spi_device *spi; | ||
53 | struct regulator *reg; | ||
54 | unsigned short vref_mv; | ||
55 | unsigned pwr_down_mask; | ||
56 | unsigned pwr_down_mode; | ||
57 | }; | ||
58 | |||
59 | /** | ||
60 | * ad5504_supported_device_ids: | ||
61 | */ | ||
62 | |||
63 | enum ad5504_supported_device_ids { | ||
64 | ID_AD5504, | ||
65 | ID_AD5501, | ||
66 | }; | ||
67 | |||
68 | #endif /* SPI_AD5504_H_ */ | ||
diff --git a/drivers/staging/iio/dac/ad5624r.h b/drivers/staging/iio/dac/ad5624r.h new file mode 100644 index 00000000000..b71c6a03e78 --- /dev/null +++ b/drivers/staging/iio/dac/ad5624r.h | |||
@@ -0,0 +1,79 @@ | |||
1 | /* | ||
2 | * AD5624R SPI DAC driver | ||
3 | * | ||
4 | * Copyright 2010-2011 Analog Devices Inc. | ||
5 | * | ||
6 | * Licensed under the GPL-2. | ||
7 | */ | ||
8 | #ifndef SPI_AD5624R_H_ | ||
9 | #define SPI_AD5624R_H_ | ||
10 | |||
11 | #define AD5624R_DAC_CHANNELS 4 | ||
12 | |||
13 | #define AD5624R_ADDR_DAC0 0x0 | ||
14 | #define AD5624R_ADDR_DAC1 0x1 | ||
15 | #define AD5624R_ADDR_DAC2 0x2 | ||
16 | #define AD5624R_ADDR_DAC3 0x3 | ||
17 | #define AD5624R_ADDR_ALL_DAC 0x7 | ||
18 | |||
19 | #define AD5624R_CMD_WRITE_INPUT_N 0x0 | ||
20 | #define AD5624R_CMD_UPDATE_DAC_N 0x1 | ||
21 | #define AD5624R_CMD_WRITE_INPUT_N_UPDATE_ALL 0x2 | ||
22 | #define AD5624R_CMD_WRITE_INPUT_N_UPDATE_N 0x3 | ||
23 | #define AD5624R_CMD_POWERDOWN_DAC 0x4 | ||
24 | #define AD5624R_CMD_RESET 0x5 | ||
25 | #define AD5624R_CMD_LDAC_SETUP 0x6 | ||
26 | #define AD5624R_CMD_INTERNAL_REFER_SETUP 0x7 | ||
27 | |||
28 | #define AD5624R_LDAC_PWRDN_NONE 0x0 | ||
29 | #define AD5624R_LDAC_PWRDN_1K 0x1 | ||
30 | #define AD5624R_LDAC_PWRDN_100K 0x2 | ||
31 | #define AD5624R_LDAC_PWRDN_3STATE 0x3 | ||
32 | |||
33 | /** | ||
34 | * struct ad5624r_chip_info - chip specific information | ||
35 | * @bits: accuracy of the DAC in bits | ||
36 | * @int_vref_mv: AD5620/40/60: the internal reference voltage | ||
37 | */ | ||
38 | |||
39 | struct ad5624r_chip_info { | ||
40 | u8 bits; | ||
41 | u16 int_vref_mv; | ||
42 | }; | ||
43 | |||
44 | /** | ||
45 | * struct ad5446_state - driver instance specific data | ||
46 | * @indio_dev: the industrial I/O device | ||
47 | * @us: spi_device | ||
48 | * @chip_info: chip model specific constants, available modes etc | ||
49 | * @reg: supply regulator | ||
50 | * @vref_mv: actual reference voltage used | ||
51 | * @pwr_down_mask power down mask | ||
52 | * @pwr_down_mode current power down mode | ||
53 | */ | ||
54 | |||
55 | struct ad5624r_state { | ||
56 | struct spi_device *us; | ||
57 | const struct ad5624r_chip_info *chip_info; | ||
58 | struct regulator *reg; | ||
59 | unsigned short vref_mv; | ||
60 | unsigned pwr_down_mask; | ||
61 | unsigned pwr_down_mode; | ||
62 | }; | ||
63 | |||
64 | /** | ||
65 | * ad5624r_supported_device_ids: | ||
66 | * The AD5624/44/64 parts are available in different | ||
67 | * fixed internal reference voltage options. | ||
68 | */ | ||
69 | |||
70 | enum ad5624r_supported_device_ids { | ||
71 | ID_AD5624R3, | ||
72 | ID_AD5644R3, | ||
73 | ID_AD5664R3, | ||
74 | ID_AD5624R5, | ||
75 | ID_AD5644R5, | ||
76 | ID_AD5664R5, | ||
77 | }; | ||
78 | |||
79 | #endif /* SPI_AD5624R_H_ */ | ||
diff --git a/drivers/staging/iio/dac/ad5624r_spi.c b/drivers/staging/iio/dac/ad5624r_spi.c new file mode 100644 index 00000000000..a5b3776718e --- /dev/null +++ b/drivers/staging/iio/dac/ad5624r_spi.c | |||
@@ -0,0 +1,336 @@ | |||
1 | /* | ||
2 | * AD5624R, AD5644R, AD5664R Digital to analog convertors spi driver | ||
3 | * | ||
4 | * Copyright 2010-2011 Analog Devices Inc. | ||
5 | * | ||
6 | * Licensed under the GPL-2. | ||
7 | */ | ||
8 | |||
9 | #include <linux/interrupt.h> | ||
10 | #include <linux/gpio.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 | |||
19 | #include "../iio.h" | ||
20 | #include "../sysfs.h" | ||
21 | #include "dac.h" | ||
22 | #include "ad5624r.h" | ||
23 | |||
24 | static const struct ad5624r_chip_info ad5624r_chip_info_tbl[] = { | ||
25 | [ID_AD5624R3] = { | ||
26 | .bits = 12, | ||
27 | .int_vref_mv = 1250, | ||
28 | }, | ||
29 | [ID_AD5644R3] = { | ||
30 | .bits = 14, | ||
31 | .int_vref_mv = 1250, | ||
32 | }, | ||
33 | [ID_AD5664R3] = { | ||
34 | .bits = 16, | ||
35 | .int_vref_mv = 1250, | ||
36 | }, | ||
37 | [ID_AD5624R5] = { | ||
38 | .bits = 12, | ||
39 | .int_vref_mv = 2500, | ||
40 | }, | ||
41 | [ID_AD5644R5] = { | ||
42 | .bits = 14, | ||
43 | .int_vref_mv = 2500, | ||
44 | }, | ||
45 | [ID_AD5664R5] = { | ||
46 | .bits = 16, | ||
47 | .int_vref_mv = 2500, | ||
48 | }, | ||
49 | }; | ||
50 | |||
51 | static int ad5624r_spi_write(struct spi_device *spi, | ||
52 | u8 cmd, u8 addr, u16 val, u8 len) | ||
53 | { | ||
54 | u32 data; | ||
55 | u8 msg[3]; | ||
56 | |||
57 | /* | ||
58 | * The input shift register is 24 bits wide. The first two bits are | ||
59 | * don't care bits. The next three are the command bits, C2 to C0, | ||
60 | * followed by the 3-bit DAC address, A2 to A0, and then the | ||
61 | * 16-, 14-, 12-bit data-word. The data-word comprises the 16-, | ||
62 | * 14-, 12-bit input code followed by 0, 2, or 4 don't care bits, | ||
63 | * for the AD5664R, AD5644R, and AD5624R, respectively. | ||
64 | */ | ||
65 | data = (0 << 22) | (cmd << 19) | (addr << 16) | (val << (16 - len)); | ||
66 | msg[0] = data >> 16; | ||
67 | msg[1] = data >> 8; | ||
68 | msg[2] = data; | ||
69 | |||
70 | return spi_write(spi, msg, 3); | ||
71 | } | ||
72 | |||
73 | static ssize_t ad5624r_write_dac(struct device *dev, | ||
74 | struct device_attribute *attr, | ||
75 | const char *buf, size_t len) | ||
76 | { | ||
77 | long readin; | ||
78 | int ret; | ||
79 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
80 | struct ad5624r_state *st = iio_priv(indio_dev); | ||
81 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | ||
82 | |||
83 | ret = strict_strtol(buf, 10, &readin); | ||
84 | if (ret) | ||
85 | return ret; | ||
86 | |||
87 | ret = ad5624r_spi_write(st->us, AD5624R_CMD_WRITE_INPUT_N_UPDATE_N, | ||
88 | this_attr->address, readin, | ||
89 | st->chip_info->bits); | ||
90 | return ret ? ret : len; | ||
91 | } | ||
92 | |||
93 | static ssize_t ad5624r_read_powerdown_mode(struct device *dev, | ||
94 | struct device_attribute *attr, char *buf) | ||
95 | { | ||
96 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
97 | struct ad5624r_state *st = iio_priv(indio_dev); | ||
98 | |||
99 | char mode[][15] = {"", "1kohm_to_gnd", "100kohm_to_gnd", "three_state"}; | ||
100 | |||
101 | return sprintf(buf, "%s\n", mode[st->pwr_down_mode]); | ||
102 | } | ||
103 | |||
104 | static ssize_t ad5624r_write_powerdown_mode(struct device *dev, | ||
105 | struct device_attribute *attr, | ||
106 | const char *buf, size_t len) | ||
107 | { | ||
108 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
109 | struct ad5624r_state *st = iio_priv(indio_dev); | ||
110 | int ret; | ||
111 | |||
112 | if (sysfs_streq(buf, "1kohm_to_gnd")) | ||
113 | st->pwr_down_mode = AD5624R_LDAC_PWRDN_1K; | ||
114 | else if (sysfs_streq(buf, "100kohm_to_gnd")) | ||
115 | st->pwr_down_mode = AD5624R_LDAC_PWRDN_100K; | ||
116 | else if (sysfs_streq(buf, "three_state")) | ||
117 | st->pwr_down_mode = AD5624R_LDAC_PWRDN_3STATE; | ||
118 | else | ||
119 | ret = -EINVAL; | ||
120 | |||
121 | return ret ? ret : len; | ||
122 | } | ||
123 | |||
124 | static ssize_t ad5624r_read_dac_powerdown(struct device *dev, | ||
125 | struct device_attribute *attr, | ||
126 | char *buf) | ||
127 | { | ||
128 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
129 | struct ad5624r_state *st = iio_priv(indio_dev); | ||
130 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | ||
131 | |||
132 | return sprintf(buf, "%d\n", | ||
133 | !!(st->pwr_down_mask & (1 << this_attr->address))); | ||
134 | } | ||
135 | |||
136 | static ssize_t ad5624r_write_dac_powerdown(struct device *dev, | ||
137 | struct device_attribute *attr, | ||
138 | const char *buf, size_t len) | ||
139 | { | ||
140 | long readin; | ||
141 | int ret; | ||
142 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
143 | struct ad5624r_state *st = iio_priv(indio_dev); | ||
144 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | ||
145 | |||
146 | ret = strict_strtol(buf, 10, &readin); | ||
147 | if (ret) | ||
148 | return ret; | ||
149 | |||
150 | if (readin == 1) | ||
151 | st->pwr_down_mask |= (1 << this_attr->address); | ||
152 | else if (!readin) | ||
153 | st->pwr_down_mask &= ~(1 << this_attr->address); | ||
154 | else | ||
155 | ret = -EINVAL; | ||
156 | |||
157 | ret = ad5624r_spi_write(st->us, AD5624R_CMD_POWERDOWN_DAC, 0, | ||
158 | (st->pwr_down_mode << 4) | | ||
159 | st->pwr_down_mask, 16); | ||
160 | |||
161 | return ret ? ret : len; | ||
162 | } | ||
163 | |||
164 | static ssize_t ad5624r_show_scale(struct device *dev, | ||
165 | struct device_attribute *attr, | ||
166 | char *buf) | ||
167 | { | ||
168 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
169 | struct ad5624r_state *st = iio_priv(indio_dev); | ||
170 | /* Corresponds to Vref / 2^(bits) */ | ||
171 | unsigned int scale_uv = (st->vref_mv * 1000) >> st->chip_info->bits; | ||
172 | |||
173 | return sprintf(buf, "%d.%03d\n", scale_uv / 1000, scale_uv % 1000); | ||
174 | } | ||
175 | static IIO_DEVICE_ATTR(out_scale, S_IRUGO, ad5624r_show_scale, NULL, 0); | ||
176 | |||
177 | static IIO_DEV_ATTR_OUT_RAW(0, ad5624r_write_dac, AD5624R_ADDR_DAC0); | ||
178 | static IIO_DEV_ATTR_OUT_RAW(1, ad5624r_write_dac, AD5624R_ADDR_DAC1); | ||
179 | static IIO_DEV_ATTR_OUT_RAW(2, ad5624r_write_dac, AD5624R_ADDR_DAC2); | ||
180 | static IIO_DEV_ATTR_OUT_RAW(3, ad5624r_write_dac, AD5624R_ADDR_DAC3); | ||
181 | |||
182 | static IIO_DEVICE_ATTR(out_powerdown_mode, S_IRUGO | | ||
183 | S_IWUSR, ad5624r_read_powerdown_mode, | ||
184 | ad5624r_write_powerdown_mode, 0); | ||
185 | |||
186 | static IIO_CONST_ATTR(out_powerdown_mode_available, | ||
187 | "1kohm_to_gnd 100kohm_to_gnd three_state"); | ||
188 | |||
189 | #define IIO_DEV_ATTR_DAC_POWERDOWN(_num, _show, _store, _addr) \ | ||
190 | IIO_DEVICE_ATTR(out##_num##_powerdown, \ | ||
191 | S_IRUGO | S_IWUSR, _show, _store, _addr) | ||
192 | |||
193 | static IIO_DEV_ATTR_DAC_POWERDOWN(0, ad5624r_read_dac_powerdown, | ||
194 | ad5624r_write_dac_powerdown, 0); | ||
195 | static IIO_DEV_ATTR_DAC_POWERDOWN(1, ad5624r_read_dac_powerdown, | ||
196 | ad5624r_write_dac_powerdown, 1); | ||
197 | static IIO_DEV_ATTR_DAC_POWERDOWN(2, ad5624r_read_dac_powerdown, | ||
198 | ad5624r_write_dac_powerdown, 2); | ||
199 | static IIO_DEV_ATTR_DAC_POWERDOWN(3, ad5624r_read_dac_powerdown, | ||
200 | ad5624r_write_dac_powerdown, 3); | ||
201 | |||
202 | static struct attribute *ad5624r_attributes[] = { | ||
203 | &iio_dev_attr_out0_raw.dev_attr.attr, | ||
204 | &iio_dev_attr_out1_raw.dev_attr.attr, | ||
205 | &iio_dev_attr_out2_raw.dev_attr.attr, | ||
206 | &iio_dev_attr_out3_raw.dev_attr.attr, | ||
207 | &iio_dev_attr_out0_powerdown.dev_attr.attr, | ||
208 | &iio_dev_attr_out1_powerdown.dev_attr.attr, | ||
209 | &iio_dev_attr_out2_powerdown.dev_attr.attr, | ||
210 | &iio_dev_attr_out3_powerdown.dev_attr.attr, | ||
211 | &iio_dev_attr_out_powerdown_mode.dev_attr.attr, | ||
212 | &iio_const_attr_out_powerdown_mode_available.dev_attr.attr, | ||
213 | &iio_dev_attr_out_scale.dev_attr.attr, | ||
214 | NULL, | ||
215 | }; | ||
216 | |||
217 | static const struct attribute_group ad5624r_attribute_group = { | ||
218 | .attrs = ad5624r_attributes, | ||
219 | }; | ||
220 | |||
221 | static const struct iio_info ad5624r_info = { | ||
222 | .attrs = &ad5624r_attribute_group, | ||
223 | .driver_module = THIS_MODULE, | ||
224 | }; | ||
225 | |||
226 | static int __devinit ad5624r_probe(struct spi_device *spi) | ||
227 | { | ||
228 | struct ad5624r_state *st; | ||
229 | struct iio_dev *indio_dev; | ||
230 | struct regulator *reg; | ||
231 | int ret, voltage_uv = 0; | ||
232 | |||
233 | reg = regulator_get(&spi->dev, "vcc"); | ||
234 | if (!IS_ERR(reg)) { | ||
235 | ret = regulator_enable(reg); | ||
236 | if (ret) | ||
237 | goto error_put_reg; | ||
238 | |||
239 | voltage_uv = regulator_get_voltage(reg); | ||
240 | } | ||
241 | indio_dev = iio_allocate_device(sizeof(*st)); | ||
242 | if (indio_dev == NULL) { | ||
243 | ret = -ENOMEM; | ||
244 | goto error_disable_reg; | ||
245 | } | ||
246 | st = iio_priv(indio_dev); | ||
247 | st->reg = reg; | ||
248 | spi_set_drvdata(spi, indio_dev); | ||
249 | st->chip_info = | ||
250 | &ad5624r_chip_info_tbl[spi_get_device_id(spi)->driver_data]; | ||
251 | |||
252 | if (voltage_uv) | ||
253 | st->vref_mv = voltage_uv / 1000; | ||
254 | else | ||
255 | st->vref_mv = st->chip_info->int_vref_mv; | ||
256 | |||
257 | st->us = spi; | ||
258 | |||
259 | indio_dev->dev.parent = &spi->dev; | ||
260 | indio_dev->name = spi_get_device_id(spi)->name; | ||
261 | indio_dev->info = &ad5624r_info; | ||
262 | indio_dev->modes = INDIO_DIRECT_MODE; | ||
263 | |||
264 | ret = iio_device_register(indio_dev); | ||
265 | if (ret) | ||
266 | goto error_free_dev; | ||
267 | |||
268 | ret = ad5624r_spi_write(spi, AD5624R_CMD_INTERNAL_REFER_SETUP, 0, | ||
269 | !!voltage_uv, 16); | ||
270 | if (ret) | ||
271 | goto error_free_dev; | ||
272 | |||
273 | return 0; | ||
274 | |||
275 | error_free_dev: | ||
276 | iio_free_device(indio_dev); | ||
277 | error_disable_reg: | ||
278 | if (!IS_ERR(reg)) | ||
279 | regulator_disable(reg); | ||
280 | error_put_reg: | ||
281 | if (!IS_ERR(reg)) | ||
282 | regulator_put(reg); | ||
283 | |||
284 | return ret; | ||
285 | } | ||
286 | |||
287 | static int __devexit ad5624r_remove(struct spi_device *spi) | ||
288 | { | ||
289 | struct iio_dev *indio_dev = spi_get_drvdata(spi); | ||
290 | struct ad5624r_state *st = iio_priv(indio_dev); | ||
291 | struct regulator *reg = st->reg; | ||
292 | |||
293 | iio_device_unregister(indio_dev); | ||
294 | if (!IS_ERR(reg)) { | ||
295 | regulator_disable(reg); | ||
296 | regulator_put(reg); | ||
297 | } | ||
298 | |||
299 | return 0; | ||
300 | } | ||
301 | |||
302 | static const struct spi_device_id ad5624r_id[] = { | ||
303 | {"ad5624r3", ID_AD5624R3}, | ||
304 | {"ad5644r3", ID_AD5644R3}, | ||
305 | {"ad5664r3", ID_AD5664R3}, | ||
306 | {"ad5624r5", ID_AD5624R5}, | ||
307 | {"ad5644r5", ID_AD5644R5}, | ||
308 | {"ad5664r5", ID_AD5664R5}, | ||
309 | {} | ||
310 | }; | ||
311 | |||
312 | static struct spi_driver ad5624r_driver = { | ||
313 | .driver = { | ||
314 | .name = "ad5624r", | ||
315 | .owner = THIS_MODULE, | ||
316 | }, | ||
317 | .probe = ad5624r_probe, | ||
318 | .remove = __devexit_p(ad5624r_remove), | ||
319 | .id_table = ad5624r_id, | ||
320 | }; | ||
321 | |||
322 | static __init int ad5624r_spi_init(void) | ||
323 | { | ||
324 | return spi_register_driver(&ad5624r_driver); | ||
325 | } | ||
326 | module_init(ad5624r_spi_init); | ||
327 | |||
328 | static __exit void ad5624r_spi_exit(void) | ||
329 | { | ||
330 | spi_unregister_driver(&ad5624r_driver); | ||
331 | } | ||
332 | module_exit(ad5624r_spi_exit); | ||
333 | |||
334 | MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); | ||
335 | MODULE_DESCRIPTION("Analog Devices AD5624/44/64R DAC spi driver"); | ||
336 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/staging/iio/dac/ad5686.c b/drivers/staging/iio/dac/ad5686.c new file mode 100644 index 00000000000..fd67cfa5edb --- /dev/null +++ b/drivers/staging/iio/dac/ad5686.c | |||
@@ -0,0 +1,497 @@ | |||
1 | /* | ||
2 | * AD5686R, AD5685R, AD5684R Digital to analog converters driver | ||
3 | * | ||
4 | * Copyright 2011 Analog Devices Inc. | ||
5 | * | ||
6 | * Licensed under the GPL-2. | ||
7 | */ | ||
8 | |||
9 | #include <linux/interrupt.h> | ||
10 | #include <linux/gpio.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 | |||
19 | #include "../iio.h" | ||
20 | #include "../sysfs.h" | ||
21 | #include "dac.h" | ||
22 | |||
23 | #define AD5686_DAC_CHANNELS 4 | ||
24 | |||
25 | #define AD5686_ADDR(x) ((x) << 16) | ||
26 | #define AD5686_CMD(x) ((x) << 20) | ||
27 | |||
28 | #define AD5686_ADDR_DAC0 0x1 | ||
29 | #define AD5686_ADDR_DAC1 0x2 | ||
30 | #define AD5686_ADDR_DAC2 0x4 | ||
31 | #define AD5686_ADDR_DAC3 0x8 | ||
32 | #define AD5686_ADDR_ALL_DAC 0xF | ||
33 | |||
34 | #define AD5686_CMD_NOOP 0x0 | ||
35 | #define AD5686_CMD_WRITE_INPUT_N 0x1 | ||
36 | #define AD5686_CMD_UPDATE_DAC_N 0x2 | ||
37 | #define AD5686_CMD_WRITE_INPUT_N_UPDATE_N 0x3 | ||
38 | #define AD5686_CMD_POWERDOWN_DAC 0x4 | ||
39 | #define AD5686_CMD_LDAC_MASK 0x5 | ||
40 | #define AD5686_CMD_RESET 0x6 | ||
41 | #define AD5686_CMD_INTERNAL_REFER_SETUP 0x7 | ||
42 | #define AD5686_CMD_DAISY_CHAIN_ENABLE 0x8 | ||
43 | #define AD5686_CMD_READBACK_ENABLE 0x9 | ||
44 | |||
45 | #define AD5686_LDAC_PWRDN_NONE 0x0 | ||
46 | #define AD5686_LDAC_PWRDN_1K 0x1 | ||
47 | #define AD5686_LDAC_PWRDN_100K 0x2 | ||
48 | #define AD5686_LDAC_PWRDN_3STATE 0x3 | ||
49 | |||
50 | /** | ||
51 | * struct ad5686_chip_info - chip specific information | ||
52 | * @int_vref_mv: AD5620/40/60: the internal reference voltage | ||
53 | * @channel: channel specification | ||
54 | */ | ||
55 | |||
56 | struct ad5686_chip_info { | ||
57 | u16 int_vref_mv; | ||
58 | struct iio_chan_spec channel[AD5686_DAC_CHANNELS]; | ||
59 | }; | ||
60 | |||
61 | /** | ||
62 | * struct ad5446_state - driver instance specific data | ||
63 | * @spi: spi_device | ||
64 | * @chip_info: chip model specific constants, available modes etc | ||
65 | * @reg: supply regulator | ||
66 | * @vref_mv: actual reference voltage used | ||
67 | * @pwr_down_mask: power down mask | ||
68 | * @pwr_down_mode: current power down mode | ||
69 | * @data: spi transfer buffers | ||
70 | */ | ||
71 | |||
72 | struct ad5686_state { | ||
73 | struct spi_device *spi; | ||
74 | const struct ad5686_chip_info *chip_info; | ||
75 | struct regulator *reg; | ||
76 | unsigned short vref_mv; | ||
77 | unsigned pwr_down_mask; | ||
78 | unsigned pwr_down_mode; | ||
79 | /* | ||
80 | * DMA (thus cache coherency maintenance) requires the | ||
81 | * transfer buffers to live in their own cache lines. | ||
82 | */ | ||
83 | |||
84 | union { | ||
85 | u32 d32; | ||
86 | u8 d8[4]; | ||
87 | } data[3] ____cacheline_aligned; | ||
88 | }; | ||
89 | |||
90 | /** | ||
91 | * ad5686_supported_device_ids: | ||
92 | */ | ||
93 | |||
94 | enum ad5686_supported_device_ids { | ||
95 | ID_AD5684, | ||
96 | ID_AD5685, | ||
97 | ID_AD5686, | ||
98 | }; | ||
99 | |||
100 | static const struct ad5686_chip_info ad5686_chip_info_tbl[] = { | ||
101 | [ID_AD5684] = { | ||
102 | .channel[0] = IIO_CHAN(IIO_OUT, 0, 1, 0, NULL, 0, 0, | ||
103 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | ||
104 | AD5686_ADDR_DAC0, | ||
105 | 0, IIO_ST('u', 12, 16, 4), 0), | ||
106 | .channel[1] = IIO_CHAN(IIO_OUT, 0, 1, 0, NULL, 1, 0, | ||
107 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | ||
108 | AD5686_ADDR_DAC1, | ||
109 | 1, IIO_ST('u', 12, 16, 4), 0), | ||
110 | .channel[2] = IIO_CHAN(IIO_OUT, 0, 1, 0, NULL, 2, 0, | ||
111 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | ||
112 | AD5686_ADDR_DAC2, | ||
113 | 2, IIO_ST('u', 12, 16, 4), 0), | ||
114 | .channel[3] = IIO_CHAN(IIO_OUT, 0, 1, 0, NULL, 3, 0, | ||
115 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | ||
116 | AD5686_ADDR_DAC3, | ||
117 | 3, IIO_ST('u', 12, 16, 4), 0), | ||
118 | .int_vref_mv = 2500, | ||
119 | }, | ||
120 | [ID_AD5685] = { | ||
121 | .channel[0] = IIO_CHAN(IIO_OUT, 0, 1, 0, NULL, 0, 0, | ||
122 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | ||
123 | AD5686_ADDR_DAC0, | ||
124 | 0, IIO_ST('u', 14, 16, 2), 0), | ||
125 | .channel[1] = IIO_CHAN(IIO_OUT, 0, 1, 0, NULL, 1, 0, | ||
126 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | ||
127 | AD5686_ADDR_DAC1, | ||
128 | 1, IIO_ST('u', 14, 16, 2), 0), | ||
129 | .channel[2] = IIO_CHAN(IIO_OUT, 0, 1, 0, NULL, 2, 0, | ||
130 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | ||
131 | AD5686_ADDR_DAC2, | ||
132 | 2, IIO_ST('u', 14, 16, 2), 0), | ||
133 | .channel[3] = IIO_CHAN(IIO_OUT, 0, 1, 0, NULL, 3, 0, | ||
134 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | ||
135 | AD5686_ADDR_DAC3, | ||
136 | 3, IIO_ST('u', 14, 16, 2), 0), | ||
137 | .int_vref_mv = 2500, | ||
138 | }, | ||
139 | [ID_AD5686] = { | ||
140 | .channel[0] = IIO_CHAN(IIO_OUT, 0, 1, 0, NULL, 0, 0, | ||
141 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | ||
142 | AD5686_ADDR_DAC0, | ||
143 | 0, IIO_ST('u', 16, 16, 0), 0), | ||
144 | .channel[1] = IIO_CHAN(IIO_OUT, 0, 1, 0, NULL, 1, 0, | ||
145 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | ||
146 | AD5686_ADDR_DAC1, | ||
147 | 1, IIO_ST('u', 16, 16, 0), 0), | ||
148 | .channel[2] = IIO_CHAN(IIO_OUT, 0, 1, 0, NULL, 2, 0, | ||
149 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | ||
150 | AD5686_ADDR_DAC2, | ||
151 | 2, IIO_ST('u', 16, 16, 0), 0), | ||
152 | .channel[3] = IIO_CHAN(IIO_OUT, 0, 1, 0, NULL, 3, 0, | ||
153 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | ||
154 | AD5686_ADDR_DAC3, | ||
155 | 3, IIO_ST('u', 16, 16, 0), 0), | ||
156 | .int_vref_mv = 2500, | ||
157 | }, | ||
158 | }; | ||
159 | |||
160 | static int ad5686_spi_write(struct ad5686_state *st, | ||
161 | u8 cmd, u8 addr, u16 val, u8 shift) | ||
162 | { | ||
163 | val <<= shift; | ||
164 | |||
165 | st->data[0].d32 = cpu_to_be32(AD5686_CMD(cmd) | | ||
166 | AD5686_ADDR(addr) | | ||
167 | val); | ||
168 | |||
169 | return spi_write(st->spi, &st->data[0].d8[1], 3); | ||
170 | } | ||
171 | |||
172 | static int ad5686_spi_read(struct ad5686_state *st, u8 addr) | ||
173 | { | ||
174 | struct spi_transfer t[] = { | ||
175 | { | ||
176 | .tx_buf = &st->data[0].d8[1], | ||
177 | .len = 3, | ||
178 | .cs_change = 1, | ||
179 | }, { | ||
180 | .tx_buf = &st->data[1].d8[1], | ||
181 | .rx_buf = &st->data[2].d8[1], | ||
182 | .len = 3, | ||
183 | }, | ||
184 | }; | ||
185 | struct spi_message m; | ||
186 | int ret; | ||
187 | |||
188 | spi_message_init(&m); | ||
189 | spi_message_add_tail(&t[0], &m); | ||
190 | spi_message_add_tail(&t[1], &m); | ||
191 | |||
192 | st->data[0].d32 = cpu_to_be32(AD5686_CMD(AD5686_CMD_READBACK_ENABLE) | | ||
193 | AD5686_ADDR(addr)); | ||
194 | st->data[1].d32 = cpu_to_be32(AD5686_CMD(AD5686_CMD_NOOP)); | ||
195 | |||
196 | ret = spi_sync(st->spi, &m); | ||
197 | if (ret < 0) | ||
198 | return ret; | ||
199 | |||
200 | return be32_to_cpu(st->data[2].d32); | ||
201 | } | ||
202 | |||
203 | static ssize_t ad5686_read_powerdown_mode(struct device *dev, | ||
204 | struct device_attribute *attr, char *buf) | ||
205 | { | ||
206 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
207 | struct ad5686_state *st = iio_priv(indio_dev); | ||
208 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | ||
209 | |||
210 | char mode[][15] = {"", "1kohm_to_gnd", "100kohm_to_gnd", "three_state"}; | ||
211 | |||
212 | return sprintf(buf, "%s\n", mode[(st->pwr_down_mode >> | ||
213 | (this_attr->address * 2)) & 0x3]); | ||
214 | } | ||
215 | |||
216 | static ssize_t ad5686_write_powerdown_mode(struct device *dev, | ||
217 | struct device_attribute *attr, | ||
218 | const char *buf, size_t len) | ||
219 | { | ||
220 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
221 | struct ad5686_state *st = iio_priv(indio_dev); | ||
222 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | ||
223 | unsigned mode; | ||
224 | |||
225 | if (sysfs_streq(buf, "1kohm_to_gnd")) | ||
226 | mode = AD5686_LDAC_PWRDN_1K; | ||
227 | else if (sysfs_streq(buf, "100kohm_to_gnd")) | ||
228 | mode = AD5686_LDAC_PWRDN_100K; | ||
229 | else if (sysfs_streq(buf, "three_state")) | ||
230 | mode = AD5686_LDAC_PWRDN_3STATE; | ||
231 | else | ||
232 | return -EINVAL; | ||
233 | |||
234 | st->pwr_down_mode &= ~(0x3 << (this_attr->address * 2)); | ||
235 | st->pwr_down_mode |= (mode << (this_attr->address * 2)); | ||
236 | |||
237 | return len; | ||
238 | } | ||
239 | |||
240 | static ssize_t ad5686_read_dac_powerdown(struct device *dev, | ||
241 | struct device_attribute *attr, | ||
242 | char *buf) | ||
243 | { | ||
244 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
245 | struct ad5686_state *st = iio_priv(indio_dev); | ||
246 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | ||
247 | |||
248 | return sprintf(buf, "%d\n", !!(st->pwr_down_mask & | ||
249 | (0x3 << (this_attr->address * 2)))); | ||
250 | } | ||
251 | |||
252 | static ssize_t ad5686_write_dac_powerdown(struct device *dev, | ||
253 | struct device_attribute *attr, | ||
254 | const char *buf, size_t len) | ||
255 | { | ||
256 | bool readin; | ||
257 | int ret; | ||
258 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
259 | struct ad5686_state *st = iio_priv(indio_dev); | ||
260 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | ||
261 | |||
262 | ret = strtobool(buf, &readin); | ||
263 | if (ret) | ||
264 | return ret; | ||
265 | |||
266 | if (readin == true) | ||
267 | st->pwr_down_mask |= (0x3 << (this_attr->address * 2)); | ||
268 | else | ||
269 | st->pwr_down_mask &= ~(0x3 << (this_attr->address * 2)); | ||
270 | |||
271 | ret = ad5686_spi_write(st, AD5686_CMD_POWERDOWN_DAC, 0, | ||
272 | st->pwr_down_mask & st->pwr_down_mode, 0); | ||
273 | |||
274 | return ret ? ret : len; | ||
275 | } | ||
276 | |||
277 | static IIO_CONST_ATTR(out_powerdown_mode_available, | ||
278 | "1kohm_to_gnd 100kohm_to_gnd three_state"); | ||
279 | |||
280 | #define IIO_DEV_ATTR_DAC_POWERDOWN_MODE(_num) \ | ||
281 | IIO_DEVICE_ATTR(out##_num##_powerdown_mode, S_IRUGO | S_IWUSR, \ | ||
282 | ad5686_read_powerdown_mode, \ | ||
283 | ad5686_write_powerdown_mode, _num) | ||
284 | |||
285 | static IIO_DEV_ATTR_DAC_POWERDOWN_MODE(0); | ||
286 | static IIO_DEV_ATTR_DAC_POWERDOWN_MODE(1); | ||
287 | static IIO_DEV_ATTR_DAC_POWERDOWN_MODE(2); | ||
288 | static IIO_DEV_ATTR_DAC_POWERDOWN_MODE(3); | ||
289 | |||
290 | #define IIO_DEV_ATTR_DAC_POWERDOWN(_num) \ | ||
291 | IIO_DEVICE_ATTR(out##_num##_powerdown, S_IRUGO | S_IWUSR, \ | ||
292 | ad5686_read_dac_powerdown, \ | ||
293 | ad5686_write_dac_powerdown, _num) | ||
294 | |||
295 | static IIO_DEV_ATTR_DAC_POWERDOWN(0); | ||
296 | static IIO_DEV_ATTR_DAC_POWERDOWN(1); | ||
297 | static IIO_DEV_ATTR_DAC_POWERDOWN(2); | ||
298 | static IIO_DEV_ATTR_DAC_POWERDOWN(3); | ||
299 | |||
300 | static struct attribute *ad5686_attributes[] = { | ||
301 | &iio_dev_attr_out0_powerdown.dev_attr.attr, | ||
302 | &iio_dev_attr_out1_powerdown.dev_attr.attr, | ||
303 | &iio_dev_attr_out2_powerdown.dev_attr.attr, | ||
304 | &iio_dev_attr_out3_powerdown.dev_attr.attr, | ||
305 | &iio_dev_attr_out0_powerdown_mode.dev_attr.attr, | ||
306 | &iio_dev_attr_out1_powerdown_mode.dev_attr.attr, | ||
307 | &iio_dev_attr_out2_powerdown_mode.dev_attr.attr, | ||
308 | &iio_dev_attr_out3_powerdown_mode.dev_attr.attr, | ||
309 | &iio_const_attr_out_powerdown_mode_available.dev_attr.attr, | ||
310 | NULL, | ||
311 | }; | ||
312 | |||
313 | static const struct attribute_group ad5686_attribute_group = { | ||
314 | .attrs = ad5686_attributes, | ||
315 | }; | ||
316 | |||
317 | static int ad5686_read_raw(struct iio_dev *indio_dev, | ||
318 | struct iio_chan_spec const *chan, | ||
319 | int *val, | ||
320 | int *val2, | ||
321 | long m) | ||
322 | { | ||
323 | struct ad5686_state *st = iio_priv(indio_dev); | ||
324 | unsigned long scale_uv; | ||
325 | int ret; | ||
326 | |||
327 | switch (m) { | ||
328 | case 0: | ||
329 | mutex_lock(&indio_dev->mlock); | ||
330 | ret = ad5686_spi_read(st, chan->address); | ||
331 | mutex_unlock(&indio_dev->mlock); | ||
332 | if (ret < 0) | ||
333 | return ret; | ||
334 | *val = ret; | ||
335 | return IIO_VAL_INT; | ||
336 | break; | ||
337 | case (1 << IIO_CHAN_INFO_SCALE_SHARED): | ||
338 | scale_uv = (st->vref_mv * 100000) | ||
339 | >> (chan->scan_type.realbits); | ||
340 | *val = scale_uv / 100000; | ||
341 | *val2 = (scale_uv % 100000) * 10; | ||
342 | return IIO_VAL_INT_PLUS_MICRO; | ||
343 | |||
344 | } | ||
345 | return -EINVAL; | ||
346 | } | ||
347 | |||
348 | static int ad5686_write_raw(struct iio_dev *indio_dev, | ||
349 | struct iio_chan_spec const *chan, | ||
350 | int val, | ||
351 | int val2, | ||
352 | long mask) | ||
353 | { | ||
354 | struct ad5686_state *st = iio_priv(indio_dev); | ||
355 | int ret; | ||
356 | |||
357 | switch (mask) { | ||
358 | case 0: | ||
359 | if (val > (1 << chan->scan_type.realbits)) | ||
360 | return -EINVAL; | ||
361 | |||
362 | mutex_lock(&indio_dev->mlock); | ||
363 | ret = ad5686_spi_write(st, | ||
364 | AD5686_CMD_WRITE_INPUT_N_UPDATE_N, | ||
365 | chan->address, | ||
366 | val, | ||
367 | chan->scan_type.shift); | ||
368 | mutex_unlock(&indio_dev->mlock); | ||
369 | break; | ||
370 | default: | ||
371 | ret = -EINVAL; | ||
372 | } | ||
373 | |||
374 | return ret; | ||
375 | } | ||
376 | |||
377 | static const struct iio_info ad5686_info = { | ||
378 | .read_raw = ad5686_read_raw, | ||
379 | .write_raw = ad5686_write_raw, | ||
380 | .attrs = &ad5686_attribute_group, | ||
381 | .driver_module = THIS_MODULE, | ||
382 | }; | ||
383 | |||
384 | static int __devinit ad5686_probe(struct spi_device *spi) | ||
385 | { | ||
386 | struct ad5686_state *st; | ||
387 | struct iio_dev *indio_dev; | ||
388 | int ret, regdone = 0, voltage_uv = 0; | ||
389 | |||
390 | indio_dev = iio_allocate_device(sizeof(*st)); | ||
391 | if (indio_dev == NULL) | ||
392 | return -ENOMEM; | ||
393 | |||
394 | st = iio_priv(indio_dev); | ||
395 | spi_set_drvdata(spi, indio_dev); | ||
396 | |||
397 | st->reg = regulator_get(&spi->dev, "vcc"); | ||
398 | if (!IS_ERR(st->reg)) { | ||
399 | ret = regulator_enable(st->reg); | ||
400 | if (ret) | ||
401 | goto error_put_reg; | ||
402 | |||
403 | voltage_uv = regulator_get_voltage(st->reg); | ||
404 | } | ||
405 | |||
406 | st->chip_info = | ||
407 | &ad5686_chip_info_tbl[spi_get_device_id(spi)->driver_data]; | ||
408 | |||
409 | if (voltage_uv) | ||
410 | st->vref_mv = voltage_uv / 1000; | ||
411 | else | ||
412 | st->vref_mv = st->chip_info->int_vref_mv; | ||
413 | |||
414 | st->spi = spi; | ||
415 | |||
416 | indio_dev->dev.parent = &spi->dev; | ||
417 | indio_dev->name = spi_get_device_id(spi)->name; | ||
418 | indio_dev->info = &ad5686_info; | ||
419 | indio_dev->modes = INDIO_DIRECT_MODE; | ||
420 | indio_dev->channels = st->chip_info->channel; | ||
421 | indio_dev->num_channels = AD5686_DAC_CHANNELS; | ||
422 | |||
423 | ret = iio_device_register(indio_dev); | ||
424 | if (ret) | ||
425 | goto error_disable_reg; | ||
426 | |||
427 | regdone = 1; | ||
428 | ret = ad5686_spi_write(st, AD5686_CMD_INTERNAL_REFER_SETUP, 0, | ||
429 | !!voltage_uv, 0); | ||
430 | if (ret) | ||
431 | goto error_disable_reg; | ||
432 | |||
433 | return 0; | ||
434 | |||
435 | error_disable_reg: | ||
436 | if (!IS_ERR(st->reg)) | ||
437 | regulator_disable(st->reg); | ||
438 | error_put_reg: | ||
439 | if (!IS_ERR(st->reg)) | ||
440 | regulator_put(st->reg); | ||
441 | |||
442 | if (regdone) | ||
443 | iio_device_unregister(indio_dev); | ||
444 | else | ||
445 | iio_free_device(indio_dev); | ||
446 | |||
447 | return ret; | ||
448 | } | ||
449 | |||
450 | static int __devexit ad5686_remove(struct spi_device *spi) | ||
451 | { | ||
452 | struct iio_dev *indio_dev = spi_get_drvdata(spi); | ||
453 | struct ad5686_state *st = iio_priv(indio_dev); | ||
454 | struct regulator *reg = st->reg; | ||
455 | |||
456 | if (!IS_ERR(reg)) { | ||
457 | regulator_disable(reg); | ||
458 | regulator_put(reg); | ||
459 | } | ||
460 | |||
461 | iio_device_unregister(indio_dev); | ||
462 | |||
463 | return 0; | ||
464 | } | ||
465 | |||
466 | static const struct spi_device_id ad5686_id[] = { | ||
467 | {"ad5684", ID_AD5684}, | ||
468 | {"ad5685", ID_AD5685}, | ||
469 | {"ad5686", ID_AD5686}, | ||
470 | {} | ||
471 | }; | ||
472 | |||
473 | static struct spi_driver ad5686_driver = { | ||
474 | .driver = { | ||
475 | .name = "ad5686", | ||
476 | .owner = THIS_MODULE, | ||
477 | }, | ||
478 | .probe = ad5686_probe, | ||
479 | .remove = __devexit_p(ad5686_remove), | ||
480 | .id_table = ad5686_id, | ||
481 | }; | ||
482 | |||
483 | static __init int ad5686_spi_init(void) | ||
484 | { | ||
485 | return spi_register_driver(&ad5686_driver); | ||
486 | } | ||
487 | module_init(ad5686_spi_init); | ||
488 | |||
489 | static __exit void ad5686_spi_exit(void) | ||
490 | { | ||
491 | spi_unregister_driver(&ad5686_driver); | ||
492 | } | ||
493 | module_exit(ad5686_spi_exit); | ||
494 | |||
495 | MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); | ||
496 | MODULE_DESCRIPTION("Analog Devices AD5686/85/84 DAC"); | ||
497 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/staging/iio/dac/ad5791.c b/drivers/staging/iio/dac/ad5791.c new file mode 100644 index 00000000000..64770d2a1b4 --- /dev/null +++ b/drivers/staging/iio/dac/ad5791.c | |||
@@ -0,0 +1,442 @@ | |||
1 | /* | ||
2 | * AD5760, AD5780, AD5781, AD5791 Voltage Output Digital to Analog Converter | ||
3 | * | ||
4 | * Copyright 2011 Analog Devices Inc. | ||
5 | * | ||
6 | * Licensed under the GPL-2. | ||
7 | */ | ||
8 | |||
9 | #include <linux/interrupt.h> | ||
10 | #include <linux/gpio.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 | |||
19 | #include "../iio.h" | ||
20 | #include "../sysfs.h" | ||
21 | #include "dac.h" | ||
22 | #include "ad5791.h" | ||
23 | |||
24 | static 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 | |||
38 | static 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 | |||
74 | static ssize_t ad5791_write_dac(struct device *dev, | ||
75 | struct device_attribute *attr, | ||
76 | const char *buf, size_t len) | ||
77 | { | ||
78 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
79 | struct ad5791_state *st = iio_priv(indio_dev); | ||
80 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | ||
81 | long readin; | ||
82 | int ret; | ||
83 | |||
84 | ret = strict_strtol(buf, 10, &readin); | ||
85 | if (ret) | ||
86 | return ret; | ||
87 | |||
88 | readin += (1 << (st->chip_info->bits - 1)); | ||
89 | readin &= AD5791_RES_MASK(st->chip_info->bits); | ||
90 | readin <<= st->chip_info->left_shift; | ||
91 | |||
92 | ret = ad5791_spi_write(st->spi, this_attr->address, readin); | ||
93 | return ret ? ret : len; | ||
94 | } | ||
95 | |||
96 | static ssize_t ad5791_read_dac(struct device *dev, | ||
97 | struct device_attribute *attr, | ||
98 | char *buf) | ||
99 | { | ||
100 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
101 | struct ad5791_state *st = iio_priv(indio_dev); | ||
102 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | ||
103 | int ret; | ||
104 | int val; | ||
105 | |||
106 | ret = ad5791_spi_read(st->spi, this_attr->address, &val); | ||
107 | if (ret) | ||
108 | return ret; | ||
109 | |||
110 | val &= AD5791_DAC_MASK; | ||
111 | val >>= st->chip_info->left_shift; | ||
112 | val -= (1 << (st->chip_info->bits - 1)); | ||
113 | |||
114 | return sprintf(buf, "%d\n", val); | ||
115 | } | ||
116 | |||
117 | static ssize_t ad5791_read_powerdown_mode(struct device *dev, | ||
118 | struct device_attribute *attr, char *buf) | ||
119 | { | ||
120 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
121 | struct ad5791_state *st = iio_priv(indio_dev); | ||
122 | |||
123 | const char mode[][14] = {"6kohm_to_gnd", "three_state"}; | ||
124 | |||
125 | return sprintf(buf, "%s\n", mode[st->pwr_down_mode]); | ||
126 | } | ||
127 | |||
128 | static ssize_t ad5791_write_powerdown_mode(struct device *dev, | ||
129 | struct device_attribute *attr, | ||
130 | const char *buf, size_t len) | ||
131 | { | ||
132 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
133 | struct ad5791_state *st = iio_priv(indio_dev); | ||
134 | int ret; | ||
135 | |||
136 | if (sysfs_streq(buf, "6kohm_to_gnd")) | ||
137 | st->pwr_down_mode = AD5791_DAC_PWRDN_6K; | ||
138 | else if (sysfs_streq(buf, "three_state")) | ||
139 | st->pwr_down_mode = AD5791_DAC_PWRDN_3STATE; | ||
140 | else | ||
141 | ret = -EINVAL; | ||
142 | |||
143 | return ret ? ret : len; | ||
144 | } | ||
145 | |||
146 | static ssize_t ad5791_read_dac_powerdown(struct device *dev, | ||
147 | struct device_attribute *attr, | ||
148 | char *buf) | ||
149 | { | ||
150 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
151 | struct ad5791_state *st = iio_priv(indio_dev); | ||
152 | |||
153 | return sprintf(buf, "%d\n", st->pwr_down); | ||
154 | } | ||
155 | |||
156 | static ssize_t ad5791_write_dac_powerdown(struct device *dev, | ||
157 | struct device_attribute *attr, | ||
158 | const char *buf, size_t len) | ||
159 | { | ||
160 | long readin; | ||
161 | int ret; | ||
162 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
163 | struct ad5791_state *st = iio_priv(indio_dev); | ||
164 | |||
165 | ret = strict_strtol(buf, 10, &readin); | ||
166 | if (ret) | ||
167 | return ret; | ||
168 | |||
169 | if (readin == 0) { | ||
170 | st->pwr_down = false; | ||
171 | st->ctrl &= ~(AD5791_CTRL_OPGND | AD5791_CTRL_DACTRI); | ||
172 | } else if (readin == 1) { | ||
173 | st->pwr_down = true; | ||
174 | if (st->pwr_down_mode == AD5791_DAC_PWRDN_6K) | ||
175 | st->ctrl |= AD5791_CTRL_OPGND; | ||
176 | else if (st->pwr_down_mode == AD5791_DAC_PWRDN_3STATE) | ||
177 | st->ctrl |= AD5791_CTRL_DACTRI; | ||
178 | } else | ||
179 | ret = -EINVAL; | ||
180 | |||
181 | ret = ad5791_spi_write(st->spi, AD5791_ADDR_CTRL, st->ctrl); | ||
182 | |||
183 | return ret ? ret : len; | ||
184 | } | ||
185 | |||
186 | static ssize_t ad5791_show_scale(struct device *dev, | ||
187 | struct device_attribute *attr, | ||
188 | char *buf) | ||
189 | { | ||
190 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
191 | struct ad5791_state *st = iio_priv(indio_dev); | ||
192 | /* Corresponds to Vref / 2^(bits) */ | ||
193 | unsigned int scale_uv = (st->vref_mv * 1000) >> st->chip_info->bits; | ||
194 | |||
195 | return sprintf(buf, "%d.%03d\n", scale_uv / 1000, scale_uv % 1000); | ||
196 | } | ||
197 | static IIO_DEVICE_ATTR(out_scale, S_IRUGO, ad5791_show_scale, NULL, 0); | ||
198 | |||
199 | static ssize_t ad5791_show_name(struct device *dev, | ||
200 | struct device_attribute *attr, | ||
201 | char *buf) | ||
202 | { | ||
203 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
204 | struct ad5791_state *st = iio_priv(indio_dev); | ||
205 | |||
206 | return sprintf(buf, "%s\n", spi_get_device_id(st->spi)->name); | ||
207 | } | ||
208 | static IIO_DEVICE_ATTR(name, S_IRUGO, ad5791_show_name, NULL, 0); | ||
209 | |||
210 | #define IIO_DEV_ATTR_OUT_RW_RAW(_num, _show, _store, _addr) \ | ||
211 | IIO_DEVICE_ATTR(out##_num##_raw, \ | ||
212 | S_IRUGO | S_IWUSR, _show, _store, _addr) | ||
213 | |||
214 | static IIO_DEV_ATTR_OUT_RW_RAW(0, ad5791_read_dac, | ||
215 | ad5791_write_dac, AD5791_ADDR_DAC0); | ||
216 | |||
217 | static IIO_DEVICE_ATTR(out_powerdown_mode, S_IRUGO | | ||
218 | S_IWUSR, ad5791_read_powerdown_mode, | ||
219 | ad5791_write_powerdown_mode, 0); | ||
220 | |||
221 | static IIO_CONST_ATTR(out_powerdown_mode_available, | ||
222 | "6kohm_to_gnd three_state"); | ||
223 | |||
224 | #define IIO_DEV_ATTR_DAC_POWERDOWN(_num, _show, _store, _addr) \ | ||
225 | IIO_DEVICE_ATTR(out##_num##_powerdown, \ | ||
226 | S_IRUGO | S_IWUSR, _show, _store, _addr) | ||
227 | |||
228 | static IIO_DEV_ATTR_DAC_POWERDOWN(0, ad5791_read_dac_powerdown, | ||
229 | ad5791_write_dac_powerdown, 0); | ||
230 | |||
231 | static struct attribute *ad5791_attributes[] = { | ||
232 | &iio_dev_attr_out0_raw.dev_attr.attr, | ||
233 | &iio_dev_attr_out0_powerdown.dev_attr.attr, | ||
234 | &iio_dev_attr_out_powerdown_mode.dev_attr.attr, | ||
235 | &iio_const_attr_out_powerdown_mode_available.dev_attr.attr, | ||
236 | &iio_dev_attr_out_scale.dev_attr.attr, | ||
237 | &iio_dev_attr_name.dev_attr.attr, | ||
238 | NULL, | ||
239 | }; | ||
240 | |||
241 | static const struct attribute_group ad5791_attribute_group = { | ||
242 | .attrs = ad5791_attributes, | ||
243 | }; | ||
244 | |||
245 | static int ad5791_get_lin_comp(unsigned int span) | ||
246 | { | ||
247 | if (span <= 10000) | ||
248 | return AD5791_LINCOMP_0_10; | ||
249 | else if (span <= 12000) | ||
250 | return AD5791_LINCOMP_10_12; | ||
251 | else if (span <= 16000) | ||
252 | return AD5791_LINCOMP_12_16; | ||
253 | else if (span <= 19000) | ||
254 | return AD5791_LINCOMP_16_19; | ||
255 | else | ||
256 | return AD5791_LINCOMP_19_20; | ||
257 | } | ||
258 | |||
259 | static int ad5780_get_lin_comp(unsigned int span) | ||
260 | { | ||
261 | if (span <= 10000) | ||
262 | return AD5780_LINCOMP_0_10; | ||
263 | else | ||
264 | return AD5780_LINCOMP_10_20; | ||
265 | } | ||
266 | |||
267 | static const struct ad5791_chip_info ad5791_chip_info_tbl[] = { | ||
268 | [ID_AD5760] = { | ||
269 | .bits = 16, | ||
270 | .left_shift = 4, | ||
271 | .get_lin_comp = ad5780_get_lin_comp, | ||
272 | }, | ||
273 | [ID_AD5780] = { | ||
274 | .bits = 18, | ||
275 | .left_shift = 2, | ||
276 | .get_lin_comp = ad5780_get_lin_comp, | ||
277 | }, | ||
278 | [ID_AD5781] = { | ||
279 | .bits = 18, | ||
280 | .left_shift = 2, | ||
281 | .get_lin_comp = ad5791_get_lin_comp, | ||
282 | }, | ||
283 | [ID_AD5791] = { | ||
284 | .bits = 20, | ||
285 | .left_shift = 0, | ||
286 | .get_lin_comp = ad5791_get_lin_comp, | ||
287 | }, | ||
288 | }; | ||
289 | |||
290 | static const struct iio_info ad5791_info = { | ||
291 | .attrs = &ad5791_attribute_group, | ||
292 | .driver_module = THIS_MODULE, | ||
293 | }; | ||
294 | |||
295 | static int __devinit ad5791_probe(struct spi_device *spi) | ||
296 | { | ||
297 | struct ad5791_platform_data *pdata = spi->dev.platform_data; | ||
298 | struct iio_dev *indio_dev; | ||
299 | struct regulator *reg_vdd, *reg_vss; | ||
300 | struct ad5791_state *st; | ||
301 | int ret, pos_voltage_uv = 0, neg_voltage_uv = 0; | ||
302 | |||
303 | reg_vdd = regulator_get(&spi->dev, "vdd"); | ||
304 | if (!IS_ERR(reg_vdd)) { | ||
305 | ret = regulator_enable(reg_vdd); | ||
306 | if (ret) | ||
307 | goto error_put_reg_pos; | ||
308 | |||
309 | pos_voltage_uv = regulator_get_voltage(reg_vdd); | ||
310 | } | ||
311 | |||
312 | reg_vss = regulator_get(&spi->dev, "vss"); | ||
313 | if (!IS_ERR(reg_vss)) { | ||
314 | ret = regulator_enable(reg_vss); | ||
315 | if (ret) | ||
316 | goto error_put_reg_neg; | ||
317 | |||
318 | neg_voltage_uv = regulator_get_voltage(reg_vss); | ||
319 | } | ||
320 | |||
321 | indio_dev = iio_allocate_device(sizeof(*st)); | ||
322 | if (indio_dev == NULL) { | ||
323 | ret = -ENOMEM; | ||
324 | goto error_disable_reg_neg; | ||
325 | } | ||
326 | st = iio_priv(indio_dev); | ||
327 | st->pwr_down = true; | ||
328 | st->spi = spi; | ||
329 | |||
330 | if (!IS_ERR(reg_vss) && !IS_ERR(reg_vdd)) | ||
331 | st->vref_mv = (pos_voltage_uv - neg_voltage_uv) / 1000; | ||
332 | else if (pdata) | ||
333 | st->vref_mv = pdata->vref_pos_mv - pdata->vref_neg_mv; | ||
334 | else | ||
335 | dev_warn(&spi->dev, "reference voltage unspecified\n"); | ||
336 | |||
337 | ret = ad5791_spi_write(spi, AD5791_ADDR_SW_CTRL, AD5791_SWCTRL_RESET); | ||
338 | if (ret) | ||
339 | goto error_free_dev; | ||
340 | |||
341 | st->chip_info = | ||
342 | &ad5791_chip_info_tbl[spi_get_device_id(spi)->driver_data]; | ||
343 | |||
344 | |||
345 | st->ctrl = AD5761_CTRL_LINCOMP(st->chip_info->get_lin_comp(st->vref_mv)) | ||
346 | | ((pdata && pdata->use_rbuf_gain2) ? 0 : AD5791_CTRL_RBUF) | | ||
347 | AD5791_CTRL_BIN2SC; | ||
348 | |||
349 | ret = ad5791_spi_write(spi, AD5791_ADDR_CTRL, st->ctrl | | ||
350 | AD5791_CTRL_OPGND | AD5791_CTRL_DACTRI); | ||
351 | if (ret) | ||
352 | goto error_free_dev; | ||
353 | |||
354 | st->reg_vdd = reg_vdd; | ||
355 | st->reg_vss = reg_vss; | ||
356 | |||
357 | spi_set_drvdata(spi, indio_dev); | ||
358 | indio_dev->dev.parent = &spi->dev; | ||
359 | indio_dev->info = &ad5791_info; | ||
360 | indio_dev->modes = INDIO_DIRECT_MODE; | ||
361 | |||
362 | ret = iio_device_register(indio_dev); | ||
363 | if (ret) | ||
364 | goto error_free_dev; | ||
365 | |||
366 | return 0; | ||
367 | |||
368 | error_free_dev: | ||
369 | iio_free_device(indio_dev); | ||
370 | |||
371 | error_disable_reg_neg: | ||
372 | if (!IS_ERR(reg_vss)) | ||
373 | regulator_disable(reg_vss); | ||
374 | error_put_reg_neg: | ||
375 | if (!IS_ERR(reg_vss)) | ||
376 | regulator_put(reg_vss); | ||
377 | |||
378 | if (!IS_ERR(reg_vdd)) | ||
379 | regulator_disable(reg_vdd); | ||
380 | error_put_reg_pos: | ||
381 | if (!IS_ERR(reg_vdd)) | ||
382 | regulator_put(reg_vdd); | ||
383 | |||
384 | error_ret: | ||
385 | return ret; | ||
386 | } | ||
387 | |||
388 | static int __devexit ad5791_remove(struct spi_device *spi) | ||
389 | { | ||
390 | struct iio_dev *indio_dev = spi_get_drvdata(spi); | ||
391 | struct ad5791_state *st = iio_priv(indio_dev); | ||
392 | struct regulator *reg_vdd = st->reg_vdd; | ||
393 | struct regulator *reg_vss = st->reg_vss; | ||
394 | |||
395 | iio_device_unregister(indio_dev); | ||
396 | |||
397 | if (!IS_ERR(st->reg_vdd)) { | ||
398 | regulator_disable(reg_vdd); | ||
399 | regulator_put(reg_vdd); | ||
400 | } | ||
401 | |||
402 | if (!IS_ERR(st->reg_vss)) { | ||
403 | regulator_disable(reg_vss); | ||
404 | regulator_put(reg_vss); | ||
405 | } | ||
406 | |||
407 | return 0; | ||
408 | } | ||
409 | |||
410 | static const struct spi_device_id ad5791_id[] = { | ||
411 | {"ad5760", ID_AD5760}, | ||
412 | {"ad5780", ID_AD5780}, | ||
413 | {"ad5781", ID_AD5781}, | ||
414 | {"ad5791", ID_AD5791}, | ||
415 | {} | ||
416 | }; | ||
417 | |||
418 | static struct spi_driver ad5791_driver = { | ||
419 | .driver = { | ||
420 | .name = "ad5791", | ||
421 | .owner = THIS_MODULE, | ||
422 | }, | ||
423 | .probe = ad5791_probe, | ||
424 | .remove = __devexit_p(ad5791_remove), | ||
425 | .id_table = ad5791_id, | ||
426 | }; | ||
427 | |||
428 | static __init int ad5791_spi_init(void) | ||
429 | { | ||
430 | return spi_register_driver(&ad5791_driver); | ||
431 | } | ||
432 | module_init(ad5791_spi_init); | ||
433 | |||
434 | static __exit void ad5791_spi_exit(void) | ||
435 | { | ||
436 | spi_unregister_driver(&ad5791_driver); | ||
437 | } | ||
438 | module_exit(ad5791_spi_exit); | ||
439 | |||
440 | MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); | ||
441 | MODULE_DESCRIPTION("Analog Devices AD5760/AD5780/AD5781/AD5791 DAC"); | ||
442 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/staging/iio/dac/ad5791.h b/drivers/staging/iio/dac/ad5791.h new file mode 100644 index 00000000000..c807f26539d --- /dev/null +++ b/drivers/staging/iio/dac/ad5791.h | |||
@@ -0,0 +1,114 @@ | |||
1 | /* | ||
2 | * AD5791 SPI DAC driver | ||
3 | * | ||
4 | * Copyright 2011 Analog Devices Inc. | ||
5 | * | ||
6 | * Licensed under the GPL-2. | ||
7 | */ | ||
8 | |||
9 | #ifndef SPI_AD5791_H_ | ||
10 | #define SPI_AD5791_H_ | ||
11 | |||
12 | #define AD5791_RES_MASK(x) ((1 << (x)) - 1) | ||
13 | #define AD5791_DAC_MASK AD5791_RES_MASK(20) | ||
14 | #define AD5791_DAC_MSB (1 << 19) | ||
15 | |||
16 | #define AD5791_CMD_READ (1 << 23) | ||
17 | #define AD5791_CMD_WRITE (0 << 23) | ||
18 | #define AD5791_ADDR(addr) ((addr) << 20) | ||
19 | |||
20 | /* Registers */ | ||
21 | #define AD5791_ADDR_NOOP 0 | ||
22 | #define AD5791_ADDR_DAC0 1 | ||
23 | #define AD5791_ADDR_CTRL 2 | ||
24 | #define AD5791_ADDR_CLRCODE 3 | ||
25 | #define AD5791_ADDR_SW_CTRL 4 | ||
26 | |||
27 | /* Control Register */ | ||
28 | #define AD5791_CTRL_RBUF (1 << 1) | ||
29 | #define AD5791_CTRL_OPGND (1 << 2) | ||
30 | #define AD5791_CTRL_DACTRI (1 << 3) | ||
31 | #define AD5791_CTRL_BIN2SC (1 << 4) | ||
32 | #define AD5791_CTRL_SDODIS (1 << 5) | ||
33 | #define AD5761_CTRL_LINCOMP(x) ((x) << 6) | ||
34 | |||
35 | #define AD5791_LINCOMP_0_10 0 | ||
36 | #define AD5791_LINCOMP_10_12 1 | ||
37 | #define AD5791_LINCOMP_12_16 2 | ||
38 | #define AD5791_LINCOMP_16_19 3 | ||
39 | #define AD5791_LINCOMP_19_20 12 | ||
40 | |||
41 | #define AD5780_LINCOMP_0_10 0 | ||
42 | #define AD5780_LINCOMP_10_20 12 | ||
43 | |||
44 | /* Software Control Register */ | ||
45 | #define AD5791_SWCTRL_LDAC (1 << 0) | ||
46 | #define AD5791_SWCTRL_CLR (1 << 1) | ||
47 | #define AD5791_SWCTRL_RESET (1 << 2) | ||
48 | |||
49 | #define AD5791_DAC_PWRDN_6K 0 | ||
50 | #define AD5791_DAC_PWRDN_3STATE 1 | ||
51 | |||
52 | /* | ||
53 | * TODO: struct ad5791_platform_data needs to go into include/linux/iio | ||
54 | */ | ||
55 | |||
56 | /** | ||
57 | * struct ad5791_platform_data - platform specific information | ||
58 | * @vref_pos_mv: Vdd Positive Analog Supply Volatge (mV) | ||
59 | * @vref_neg_mv: Vdd Negative Analog Supply Volatge (mV) | ||
60 | * @use_rbuf_gain2: ext. amplifier connected in gain of two configuration | ||
61 | */ | ||
62 | |||
63 | struct ad5791_platform_data { | ||
64 | u16 vref_pos_mv; | ||
65 | u16 vref_neg_mv; | ||
66 | bool use_rbuf_gain2; | ||
67 | }; | ||
68 | |||
69 | /** | ||
70 | * struct ad5791_chip_info - chip specific information | ||
71 | * @bits: accuracy of the DAC in bits | ||
72 | * @left_shift: number of bits the datum must be shifted | ||
73 | * @get_lin_comp: function pointer to the device specific function | ||
74 | */ | ||
75 | |||
76 | struct ad5791_chip_info { | ||
77 | u8 bits; | ||
78 | u8 left_shift; | ||
79 | int (*get_lin_comp) (unsigned int span); | ||
80 | }; | ||
81 | |||
82 | /** | ||
83 | * struct ad5791_state - driver instance specific data | ||
84 | * @us: spi_device | ||
85 | * @reg_vdd: positive supply regulator | ||
86 | * @reg_vss: negative supply regulator | ||
87 | * @chip_info: chip model specific constants | ||
88 | * @vref_mv: actual reference voltage used | ||
89 | * @pwr_down_mode current power down mode | ||
90 | */ | ||
91 | |||
92 | struct ad5791_state { | ||
93 | struct spi_device *spi; | ||
94 | struct regulator *reg_vdd; | ||
95 | struct regulator *reg_vss; | ||
96 | const struct ad5791_chip_info *chip_info; | ||
97 | unsigned short vref_mv; | ||
98 | unsigned ctrl; | ||
99 | unsigned pwr_down_mode; | ||
100 | bool pwr_down; | ||
101 | }; | ||
102 | |||
103 | /** | ||
104 | * ad5791_supported_device_ids: | ||
105 | */ | ||
106 | |||
107 | enum ad5791_supported_device_ids { | ||
108 | ID_AD5760, | ||
109 | ID_AD5780, | ||
110 | ID_AD5781, | ||
111 | ID_AD5791, | ||
112 | }; | ||
113 | |||
114 | #endif /* SPI_AD5791_H_ */ | ||
diff --git a/drivers/staging/iio/dac/dac.h b/drivers/staging/iio/dac/dac.h new file mode 100644 index 00000000000..1d82f353241 --- /dev/null +++ b/drivers/staging/iio/dac/dac.h | |||
@@ -0,0 +1,6 @@ | |||
1 | /* | ||
2 | * dac.h - sysfs attributes associated with DACs | ||
3 | */ | ||
4 | |||
5 | #define IIO_DEV_ATTR_OUT_RAW(_num, _store, _addr) \ | ||
6 | IIO_DEVICE_ATTR(out##_num##_raw, S_IWUSR, NULL, _store, _addr) | ||
diff --git a/drivers/staging/iio/dac/max517.c b/drivers/staging/iio/dac/max517.c new file mode 100644 index 00000000000..ed5d351b238 --- /dev/null +++ b/drivers/staging/iio/dac/max517.c | |||
@@ -0,0 +1,295 @@ | |||
1 | /* | ||
2 | * max517.c - Support for Maxim MAX517, MAX518 and MAX519 | ||
3 | * | ||
4 | * Copyright (C) 2010, 2011 Roland Stigge <stigge@antcom.de> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | */ | ||
20 | |||
21 | #include <linux/module.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/jiffies.h> | ||
25 | #include <linux/i2c.h> | ||
26 | #include <linux/err.h> | ||
27 | |||
28 | #include "../iio.h" | ||
29 | #include "dac.h" | ||
30 | |||
31 | #include "max517.h" | ||
32 | |||
33 | #define MAX517_DRV_NAME "max517" | ||
34 | |||
35 | /* Commands */ | ||
36 | #define COMMAND_CHANNEL0 0x00 | ||
37 | #define COMMAND_CHANNEL1 0x01 /* for MAX518 and MAX519 */ | ||
38 | #define COMMAND_PD 0x08 /* Power Down */ | ||
39 | |||
40 | enum max517_device_ids { | ||
41 | ID_MAX517, | ||
42 | ID_MAX518, | ||
43 | ID_MAX519, | ||
44 | }; | ||
45 | |||
46 | struct max517_data { | ||
47 | struct iio_dev *indio_dev; | ||
48 | struct i2c_client *client; | ||
49 | unsigned short vref_mv[2]; | ||
50 | }; | ||
51 | |||
52 | /* | ||
53 | * channel: bit 0: channel 1 | ||
54 | * bit 1: channel 2 | ||
55 | * (this way, it's possible to set both channels at once) | ||
56 | */ | ||
57 | static ssize_t max517_set_value(struct device *dev, | ||
58 | struct device_attribute *attr, | ||
59 | const char *buf, size_t count, int channel) | ||
60 | { | ||
61 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
62 | struct max517_data *data = iio_priv(dev_info); | ||
63 | struct i2c_client *client = data->client; | ||
64 | u8 outbuf[4]; /* 1x or 2x command + value */ | ||
65 | int outbuf_size = 0; | ||
66 | int res; | ||
67 | long val; | ||
68 | |||
69 | res = strict_strtol(buf, 10, &val); | ||
70 | |||
71 | if (res) | ||
72 | return res; | ||
73 | |||
74 | if (val < 0 || val > 255) | ||
75 | return -EINVAL; | ||
76 | |||
77 | if (channel & 1) { | ||
78 | outbuf[outbuf_size++] = COMMAND_CHANNEL0; | ||
79 | outbuf[outbuf_size++] = val; | ||
80 | } | ||
81 | if (channel & 2) { | ||
82 | outbuf[outbuf_size++] = COMMAND_CHANNEL1; | ||
83 | outbuf[outbuf_size++] = val; | ||
84 | } | ||
85 | |||
86 | /* | ||
87 | * At this point, there are always 1 or 2 two-byte commands in | ||
88 | * outbuf. With 2 commands, the device can set two outputs | ||
89 | * simultaneously, latching the values upon the end of the I2C | ||
90 | * transfer. | ||
91 | */ | ||
92 | |||
93 | res = i2c_master_send(client, outbuf, outbuf_size); | ||
94 | if (res < 0) | ||
95 | return res; | ||
96 | |||
97 | return count; | ||
98 | } | ||
99 | |||
100 | static ssize_t max517_set_value_1(struct device *dev, | ||
101 | struct device_attribute *attr, | ||
102 | const char *buf, size_t count) | ||
103 | { | ||
104 | return max517_set_value(dev, attr, buf, count, 1); | ||
105 | } | ||
106 | static IIO_DEV_ATTR_OUT_RAW(1, max517_set_value_1, 0); | ||
107 | |||
108 | static ssize_t max517_set_value_2(struct device *dev, | ||
109 | struct device_attribute *attr, | ||
110 | const char *buf, size_t count) | ||
111 | { | ||
112 | return max517_set_value(dev, attr, buf, count, 2); | ||
113 | } | ||
114 | static IIO_DEV_ATTR_OUT_RAW(2, max517_set_value_2, 1); | ||
115 | |||
116 | static ssize_t max517_set_value_both(struct device *dev, | ||
117 | struct device_attribute *attr, | ||
118 | const char *buf, size_t count) | ||
119 | { | ||
120 | return max517_set_value(dev, attr, buf, count, 3); | ||
121 | } | ||
122 | static IIO_DEVICE_ATTR_NAMED(out1and2_raw, out1&2_raw, S_IWUSR, NULL, | ||
123 | max517_set_value_both, -1); | ||
124 | |||
125 | static ssize_t max517_show_scale(struct device *dev, | ||
126 | struct device_attribute *attr, | ||
127 | char *buf, int channel) | ||
128 | { | ||
129 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
130 | struct max517_data *data = iio_priv(dev_info); | ||
131 | /* Corresponds to Vref / 2^(bits) */ | ||
132 | unsigned int scale_uv = (data->vref_mv[channel - 1] * 1000) >> 8; | ||
133 | |||
134 | return sprintf(buf, "%d.%03d\n", scale_uv / 1000, scale_uv % 1000); | ||
135 | } | ||
136 | |||
137 | static ssize_t max517_show_scale1(struct device *dev, | ||
138 | struct device_attribute *attr, | ||
139 | char *buf) | ||
140 | { | ||
141 | return max517_show_scale(dev, attr, buf, 1); | ||
142 | } | ||
143 | static IIO_DEVICE_ATTR(out1_scale, S_IRUGO, max517_show_scale1, NULL, 0); | ||
144 | |||
145 | static ssize_t max517_show_scale2(struct device *dev, | ||
146 | struct device_attribute *attr, | ||
147 | char *buf) | ||
148 | { | ||
149 | return max517_show_scale(dev, attr, buf, 2); | ||
150 | } | ||
151 | static IIO_DEVICE_ATTR(out2_scale, S_IRUGO, max517_show_scale2, NULL, 0); | ||
152 | |||
153 | /* On MAX517 variant, we have one output */ | ||
154 | static struct attribute *max517_attributes[] = { | ||
155 | &iio_dev_attr_out1_raw.dev_attr.attr, | ||
156 | &iio_dev_attr_out1_scale.dev_attr.attr, | ||
157 | NULL | ||
158 | }; | ||
159 | |||
160 | static struct attribute_group max517_attribute_group = { | ||
161 | .attrs = max517_attributes, | ||
162 | }; | ||
163 | |||
164 | /* On MAX518 and MAX519 variant, we have two outputs */ | ||
165 | static struct attribute *max518_attributes[] = { | ||
166 | &iio_dev_attr_out1_raw.dev_attr.attr, | ||
167 | &iio_dev_attr_out1_scale.dev_attr.attr, | ||
168 | &iio_dev_attr_out2_raw.dev_attr.attr, | ||
169 | &iio_dev_attr_out2_scale.dev_attr.attr, | ||
170 | &iio_dev_attr_out1and2_raw.dev_attr.attr, | ||
171 | NULL | ||
172 | }; | ||
173 | |||
174 | static struct attribute_group max518_attribute_group = { | ||
175 | .attrs = max518_attributes, | ||
176 | }; | ||
177 | |||
178 | static int max517_suspend(struct i2c_client *client, pm_message_t mesg) | ||
179 | { | ||
180 | u8 outbuf = COMMAND_PD; | ||
181 | |||
182 | return i2c_master_send(client, &outbuf, 1); | ||
183 | } | ||
184 | |||
185 | static int max517_resume(struct i2c_client *client) | ||
186 | { | ||
187 | u8 outbuf = 0; | ||
188 | |||
189 | return i2c_master_send(client, &outbuf, 1); | ||
190 | } | ||
191 | |||
192 | static const struct iio_info max517_info = { | ||
193 | .attrs = &max517_attribute_group, | ||
194 | .driver_module = THIS_MODULE, | ||
195 | }; | ||
196 | |||
197 | static const struct iio_info max518_info = { | ||
198 | .attrs = &max518_attribute_group, | ||
199 | .driver_module = THIS_MODULE, | ||
200 | }; | ||
201 | |||
202 | static int max517_probe(struct i2c_client *client, | ||
203 | const struct i2c_device_id *id) | ||
204 | { | ||
205 | struct max517_data *data; | ||
206 | struct iio_dev *indio_dev; | ||
207 | struct max517_platform_data *platform_data = client->dev.platform_data; | ||
208 | int err; | ||
209 | |||
210 | indio_dev = iio_allocate_device(sizeof(*data)); | ||
211 | if (indio_dev == NULL) { | ||
212 | err = -ENOMEM; | ||
213 | goto exit; | ||
214 | } | ||
215 | data = iio_priv(indio_dev); | ||
216 | i2c_set_clientdata(client, indio_dev); | ||
217 | data->client = client; | ||
218 | |||
219 | /* establish that the iio_dev is a child of the i2c device */ | ||
220 | indio_dev->dev.parent = &client->dev; | ||
221 | |||
222 | /* reduced attribute set for MAX517 */ | ||
223 | if (id->driver_data == ID_MAX517) | ||
224 | indio_dev->info = &max517_info; | ||
225 | else | ||
226 | indio_dev->info = &max518_info; | ||
227 | indio_dev->modes = INDIO_DIRECT_MODE; | ||
228 | |||
229 | /* | ||
230 | * Reference voltage on MAX518 and default is 5V, else take vref_mv | ||
231 | * from platform_data | ||
232 | */ | ||
233 | if (id->driver_data == ID_MAX518 || !platform_data) { | ||
234 | data->vref_mv[0] = data->vref_mv[1] = 5000; /* mV */ | ||
235 | } else { | ||
236 | data->vref_mv[0] = platform_data->vref_mv[0]; | ||
237 | data->vref_mv[1] = platform_data->vref_mv[1]; | ||
238 | } | ||
239 | |||
240 | err = iio_device_register(indio_dev); | ||
241 | if (err) | ||
242 | goto exit_free_device; | ||
243 | |||
244 | dev_info(&client->dev, "DAC registered\n"); | ||
245 | |||
246 | return 0; | ||
247 | |||
248 | exit_free_device: | ||
249 | iio_free_device(indio_dev); | ||
250 | exit: | ||
251 | return err; | ||
252 | } | ||
253 | |||
254 | static int max517_remove(struct i2c_client *client) | ||
255 | { | ||
256 | iio_free_device(i2c_get_clientdata(client)); | ||
257 | |||
258 | return 0; | ||
259 | } | ||
260 | |||
261 | static const struct i2c_device_id max517_id[] = { | ||
262 | { "max517", ID_MAX517 }, | ||
263 | { "max518", ID_MAX518 }, | ||
264 | { "max519", ID_MAX519 }, | ||
265 | { } | ||
266 | }; | ||
267 | MODULE_DEVICE_TABLE(i2c, max517_id); | ||
268 | |||
269 | static struct i2c_driver max517_driver = { | ||
270 | .driver = { | ||
271 | .name = MAX517_DRV_NAME, | ||
272 | }, | ||
273 | .probe = max517_probe, | ||
274 | .remove = max517_remove, | ||
275 | .suspend = max517_suspend, | ||
276 | .resume = max517_resume, | ||
277 | .id_table = max517_id, | ||
278 | }; | ||
279 | |||
280 | static int __init max517_init(void) | ||
281 | { | ||
282 | return i2c_add_driver(&max517_driver); | ||
283 | } | ||
284 | |||
285 | static void __exit max517_exit(void) | ||
286 | { | ||
287 | i2c_del_driver(&max517_driver); | ||
288 | } | ||
289 | |||
290 | MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>"); | ||
291 | MODULE_DESCRIPTION("MAX517/MAX518/MAX519 8-bit DAC"); | ||
292 | MODULE_LICENSE("GPL"); | ||
293 | |||
294 | module_init(max517_init); | ||
295 | module_exit(max517_exit); | ||
diff --git a/drivers/staging/iio/dac/max517.h b/drivers/staging/iio/dac/max517.h new file mode 100644 index 00000000000..8106cf24642 --- /dev/null +++ b/drivers/staging/iio/dac/max517.h | |||
@@ -0,0 +1,19 @@ | |||
1 | /* | ||
2 | * MAX517 DAC driver | ||
3 | * | ||
4 | * Copyright 2011 Roland Stigge <stigge@antcom.de> | ||
5 | * | ||
6 | * Licensed under the GPL-2 or later. | ||
7 | */ | ||
8 | #ifndef IIO_DAC_MAX517_H_ | ||
9 | #define IIO_DAC_MAX517_H_ | ||
10 | |||
11 | /* | ||
12 | * TODO: struct max517_platform_data needs to go into include/linux/iio | ||
13 | */ | ||
14 | |||
15 | struct max517_platform_data { | ||
16 | u16 vref_mv[2]; | ||
17 | }; | ||
18 | |||
19 | #endif /* IIO_DAC_MAX517_H_ */ | ||