aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iio/dac/ad5446.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-07-26 14:14:49 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-07-26 14:14:49 -0400
commitb13bc8dda81c54a66a1c84e66f60b8feba659f28 (patch)
tree100a26eada424fa5d9b0e5eaaf4e23b8fa036fc8 /drivers/iio/dac/ad5446.c
parent9fc377799bc9bfd8d5cb35d0d1ea2e2458cbdbb3 (diff)
parent419e9266884fa853179ab726c27a63a9d3ae46e3 (diff)
Merge tag 'staging-3.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging
Pull staging tree patches from Greg Kroah-Hartman: "Here's the big staging tree merge for the 3.6-rc1 merge window. There are some patches in here outside of drivers/staging/, notibly the iio code (which is still stradeling the staging / not staging boundry), the pstore code, and the tracing code. All of these have gotten acks from the various subsystem maintainers to be included in this tree. The pstore and tracing patches are related, and are coming here as they replace one of the android staging drivers. Otherwise, the normal staging mess. Lots of cleanups and a few new drivers (some iio drivers, and the large csr wireless driver abomination.) Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>" Fixed up trivial conflicts in drivers/staging/comedi/drivers/s626.h and drivers/staging/gdm72xx/netlink_k.c * tag 'staging-3.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging: (1108 commits) staging: csr: delete a bunch of unused library functions staging: csr: remove csr_utf16.c staging: csr: remove csr_pmem.h staging: csr: remove CsrPmemAlloc staging: csr: remove CsrPmemFree() staging: csr: remove CsrMemAllocDma() staging: csr: remove CsrMemCalloc() staging: csr: remove CsrMemAlloc() staging: csr: remove CsrMemFree() and CsrMemFreeDma() staging: csr: remove csr_util.h staging: csr: remove CsrOffSetOf() stating: csr: remove unneeded #includes in csr_util.c staging: csr: make CsrUInt16ToHex static staging: csr: remove CsrMemCpy() staging: csr: remove CsrStrLen() staging: csr: remove CsrVsnprintf() staging: csr: remove CsrStrDup staging: csr: remove CsrStrChr() staging: csr: remove CsrStrNCmp staging: csr: remove CsrStrCmp ...
Diffstat (limited to 'drivers/iio/dac/ad5446.c')
-rw-r--r--drivers/iio/dac/ad5446.c393
1 files changed, 393 insertions, 0 deletions
diff --git a/drivers/iio/dac/ad5446.c b/drivers/iio/dac/ad5446.c
new file mode 100644
index 000000000000..2ca5059ef89e
--- /dev/null
+++ b/drivers/iio/dac/ad5446.c
@@ -0,0 +1,393 @@
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#include <linux/module.h>
20
21#include <linux/iio/iio.h>
22#include <linux/iio/sysfs.h>
23
24#include "ad5446.h"
25
26static int ad5446_write(struct ad5446_state *st, unsigned val)
27{
28 __be16 data = cpu_to_be16(val);
29 return spi_write(st->spi, &data, sizeof(data));
30}
31
32static int ad5660_write(struct ad5446_state *st, unsigned val)
33{
34 uint8_t data[3];
35
36 data[0] = (val >> 16) & 0xFF;
37 data[1] = (val >> 8) & 0xFF;
38 data[2] = val & 0xFF;
39
40 return spi_write(st->spi, data, sizeof(data));
41}
42
43static const char * const ad5446_powerdown_modes[] = {
44 "1kohm_to_gnd", "100kohm_to_gnd", "three_state"
45};
46
47static int ad5446_set_powerdown_mode(struct iio_dev *indio_dev,
48 const struct iio_chan_spec *chan, unsigned int mode)
49{
50 struct ad5446_state *st = iio_priv(indio_dev);
51
52 st->pwr_down_mode = mode + 1;
53
54 return 0;
55}
56
57static int ad5446_get_powerdown_mode(struct iio_dev *indio_dev,
58 const struct iio_chan_spec *chan)
59{
60 struct ad5446_state *st = iio_priv(indio_dev);
61
62 return st->pwr_down_mode - 1;
63}
64
65static const struct iio_enum ad5446_powerdown_mode_enum = {
66 .items = ad5446_powerdown_modes,
67 .num_items = ARRAY_SIZE(ad5446_powerdown_modes),
68 .get = ad5446_get_powerdown_mode,
69 .set = ad5446_set_powerdown_mode,
70};
71
72static ssize_t ad5446_read_dac_powerdown(struct iio_dev *indio_dev,
73 uintptr_t private,
74 const struct iio_chan_spec *chan,
75 char *buf)
76{
77 struct ad5446_state *st = iio_priv(indio_dev);
78
79 return sprintf(buf, "%d\n", st->pwr_down);
80}
81
82static ssize_t ad5446_write_dac_powerdown(struct iio_dev *indio_dev,
83 uintptr_t private,
84 const struct iio_chan_spec *chan,
85 const char *buf, size_t len)
86{
87 struct ad5446_state *st = iio_priv(indio_dev);
88 unsigned int shift;
89 unsigned int val;
90 bool powerdown;
91 int ret;
92
93 ret = strtobool(buf, &powerdown);
94 if (ret)
95 return ret;
96
97 mutex_lock(&indio_dev->mlock);
98 st->pwr_down = powerdown;
99
100 if (st->pwr_down) {
101 shift = chan->scan_type.realbits + chan->scan_type.shift;
102 val = st->pwr_down_mode << shift;
103 } else {
104 val = st->cached_val;
105 }
106
107 ret = st->chip_info->write(st, val);
108 mutex_unlock(&indio_dev->mlock);
109
110 return ret ? ret : len;
111}
112
113static const struct iio_chan_spec_ext_info ad5064_ext_info_powerdown[] = {
114 {
115 .name = "powerdown",
116 .read = ad5446_read_dac_powerdown,
117 .write = ad5446_write_dac_powerdown,
118 },
119 IIO_ENUM("powerdown_mode", false, &ad5446_powerdown_mode_enum),
120 IIO_ENUM_AVAILABLE("powerdown_mode", &ad5446_powerdown_mode_enum),
121 { },
122};
123
124#define _AD5446_CHANNEL(bits, storage, shift, ext) { \
125 .type = IIO_VOLTAGE, \
126 .indexed = 1, \
127 .output = 1, \
128 .channel = 0, \
129 .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
130 IIO_CHAN_INFO_SCALE_SHARED_BIT, \
131 .scan_type = IIO_ST('u', (bits), (storage), (shift)), \
132 .ext_info = (ext), \
133}
134
135#define AD5446_CHANNEL(bits, storage, shift) \
136 _AD5446_CHANNEL(bits, storage, shift, NULL)
137
138#define AD5446_CHANNEL_POWERDOWN(bits, storage, shift) \
139 _AD5446_CHANNEL(bits, storage, shift, ad5064_ext_info_powerdown)
140
141static const struct ad5446_chip_info ad5446_chip_info_tbl[] = {
142 [ID_AD5444] = {
143 .channel = AD5446_CHANNEL(12, 16, 2),
144 .write = ad5446_write,
145 },
146 [ID_AD5446] = {
147 .channel = AD5446_CHANNEL(14, 16, 0),
148 .write = ad5446_write,
149 },
150 [ID_AD5450] = {
151 .channel = AD5446_CHANNEL(8, 16, 6),
152 .write = ad5446_write,
153 },
154 [ID_AD5451] = {
155 .channel = AD5446_CHANNEL(10, 16, 4),
156 .write = ad5446_write,
157 },
158 [ID_AD5541A] = {
159 .channel = AD5446_CHANNEL(16, 16, 0),
160 .write = ad5446_write,
161 },
162 [ID_AD5512A] = {
163 .channel = AD5446_CHANNEL(12, 16, 4),
164 .write = ad5446_write,
165 },
166 [ID_AD5553] = {
167 .channel = AD5446_CHANNEL(14, 16, 0),
168 .write = ad5446_write,
169 },
170 [ID_AD5601] = {
171 .channel = AD5446_CHANNEL_POWERDOWN(8, 16, 6),
172 .write = ad5446_write,
173 },
174 [ID_AD5611] = {
175 .channel = AD5446_CHANNEL_POWERDOWN(10, 16, 4),
176 .write = ad5446_write,
177 },
178 [ID_AD5621] = {
179 .channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2),
180 .write = ad5446_write,
181 },
182 [ID_AD5620_2500] = {
183 .channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2),
184 .int_vref_mv = 2500,
185 .write = ad5446_write,
186 },
187 [ID_AD5620_1250] = {
188 .channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2),
189 .int_vref_mv = 1250,
190 .write = ad5446_write,
191 },
192 [ID_AD5640_2500] = {
193 .channel = AD5446_CHANNEL_POWERDOWN(14, 16, 0),
194 .int_vref_mv = 2500,
195 .write = ad5446_write,
196 },
197 [ID_AD5640_1250] = {
198 .channel = AD5446_CHANNEL_POWERDOWN(14, 16, 0),
199 .int_vref_mv = 1250,
200 .write = ad5446_write,
201 },
202 [ID_AD5660_2500] = {
203 .channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0),
204 .int_vref_mv = 2500,
205 .write = ad5660_write,
206 },
207 [ID_AD5660_1250] = {
208 .channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0),
209 .int_vref_mv = 1250,
210 .write = ad5660_write,
211 },
212 [ID_AD5662] = {
213 .channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0),
214 .write = ad5660_write,
215 },
216};
217
218static int ad5446_read_raw(struct iio_dev *indio_dev,
219 struct iio_chan_spec const *chan,
220 int *val,
221 int *val2,
222 long m)
223{
224 struct ad5446_state *st = iio_priv(indio_dev);
225 unsigned long scale_uv;
226
227 switch (m) {
228 case IIO_CHAN_INFO_RAW:
229 *val = st->cached_val;
230 return IIO_VAL_INT;
231 case IIO_CHAN_INFO_SCALE:
232 scale_uv = (st->vref_mv * 1000) >> chan->scan_type.realbits;
233 *val = scale_uv / 1000;
234 *val2 = (scale_uv % 1000) * 1000;
235 return IIO_VAL_INT_PLUS_MICRO;
236
237 }
238 return -EINVAL;
239}
240
241static int ad5446_write_raw(struct iio_dev *indio_dev,
242 struct iio_chan_spec const *chan,
243 int val,
244 int val2,
245 long mask)
246{
247 struct ad5446_state *st = iio_priv(indio_dev);
248 int ret = 0;
249
250 switch (mask) {
251 case IIO_CHAN_INFO_RAW:
252 if (val >= (1 << chan->scan_type.realbits) || val < 0)
253 return -EINVAL;
254
255 val <<= chan->scan_type.shift;
256 mutex_lock(&indio_dev->mlock);
257 st->cached_val = val;
258 if (!st->pwr_down)
259 ret = st->chip_info->write(st, val);
260 mutex_unlock(&indio_dev->mlock);
261 break;
262 default:
263 ret = -EINVAL;
264 }
265
266 return ret;
267}
268
269static const struct iio_info ad5446_info = {
270 .read_raw = ad5446_read_raw,
271 .write_raw = ad5446_write_raw,
272 .driver_module = THIS_MODULE,
273};
274
275static int __devinit ad5446_probe(struct spi_device *spi)
276{
277 struct ad5446_state *st;
278 struct iio_dev *indio_dev;
279 struct regulator *reg;
280 int ret, voltage_uv = 0;
281
282 reg = regulator_get(&spi->dev, "vcc");
283 if (!IS_ERR(reg)) {
284 ret = regulator_enable(reg);
285 if (ret)
286 goto error_put_reg;
287
288 voltage_uv = regulator_get_voltage(reg);
289 }
290
291 indio_dev = iio_device_alloc(sizeof(*st));
292 if (indio_dev == NULL) {
293 ret = -ENOMEM;
294 goto error_disable_reg;
295 }
296 st = iio_priv(indio_dev);
297 st->chip_info =
298 &ad5446_chip_info_tbl[spi_get_device_id(spi)->driver_data];
299
300 spi_set_drvdata(spi, indio_dev);
301 st->reg = reg;
302 st->spi = spi;
303
304 /* Establish that the iio_dev is a child of the spi device */
305 indio_dev->dev.parent = &spi->dev;
306 indio_dev->name = spi_get_device_id(spi)->name;
307 indio_dev->info = &ad5446_info;
308 indio_dev->modes = INDIO_DIRECT_MODE;
309 indio_dev->channels = &st->chip_info->channel;
310 indio_dev->num_channels = 1;
311
312 st->pwr_down_mode = MODE_PWRDWN_1k;
313
314 if (st->chip_info->int_vref_mv)
315 st->vref_mv = st->chip_info->int_vref_mv;
316 else if (voltage_uv)
317 st->vref_mv = voltage_uv / 1000;
318 else
319 dev_warn(&spi->dev, "reference voltage unspecified\n");
320
321 ret = iio_device_register(indio_dev);
322 if (ret)
323 goto error_free_device;
324
325 return 0;
326
327error_free_device:
328 iio_device_free(indio_dev);
329error_disable_reg:
330 if (!IS_ERR(reg))
331 regulator_disable(reg);
332error_put_reg:
333 if (!IS_ERR(reg))
334 regulator_put(reg);
335
336 return ret;
337}
338
339static int ad5446_remove(struct spi_device *spi)
340{
341 struct iio_dev *indio_dev = spi_get_drvdata(spi);
342 struct ad5446_state *st = iio_priv(indio_dev);
343
344 iio_device_unregister(indio_dev);
345 if (!IS_ERR(st->reg)) {
346 regulator_disable(st->reg);
347 regulator_put(st->reg);
348 }
349 iio_device_free(indio_dev);
350
351 return 0;
352}
353
354static const struct spi_device_id ad5446_id[] = {
355 {"ad5444", ID_AD5444},
356 {"ad5446", ID_AD5446},
357 {"ad5450", ID_AD5450},
358 {"ad5451", ID_AD5451},
359 {"ad5452", ID_AD5444}, /* ad5452 is compatible to the ad5444 */
360 {"ad5453", ID_AD5446}, /* ad5453 is compatible to the ad5446 */
361 {"ad5512a", ID_AD5512A},
362 {"ad5541a", ID_AD5541A},
363 {"ad5542a", ID_AD5541A}, /* ad5541a and ad5542a are compatible */
364 {"ad5543", ID_AD5541A}, /* ad5541a and ad5543 are compatible */
365 {"ad5553", ID_AD5553},
366 {"ad5601", ID_AD5601},
367 {"ad5611", ID_AD5611},
368 {"ad5621", ID_AD5621},
369 {"ad5620-2500", ID_AD5620_2500}, /* AD5620/40/60: */
370 {"ad5620-1250", ID_AD5620_1250}, /* part numbers may look differently */
371 {"ad5640-2500", ID_AD5640_2500},
372 {"ad5640-1250", ID_AD5640_1250},
373 {"ad5660-2500", ID_AD5660_2500},
374 {"ad5660-1250", ID_AD5660_1250},
375 {"ad5662", ID_AD5662},
376 {}
377};
378MODULE_DEVICE_TABLE(spi, ad5446_id);
379
380static struct spi_driver ad5446_driver = {
381 .driver = {
382 .name = "ad5446",
383 .owner = THIS_MODULE,
384 },
385 .probe = ad5446_probe,
386 .remove = __devexit_p(ad5446_remove),
387 .id_table = ad5446_id,
388};
389module_spi_driver(ad5446_driver);
390
391MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
392MODULE_DESCRIPTION("Analog Devices AD5444/AD5446 DAC");
393MODULE_LICENSE("GPL v2");