blob: 4e955ed9451d1974d27aab2187424a035b7e97ab [file] [log] [blame]
Michael Hennerich69d900a2011-04-18 09:40:58 +02001/*
Lars-Peter Clausen9d41c5b2011-12-09 17:12:42 +01002 * AD5760, AD5780, AD5781, AD5790, AD5791 Voltage Output Digital to Analog
3 * Converter
Michael Hennerich69d900a2011-04-18 09:40:58 +02004 *
5 * Copyright 2011 Analog Devices Inc.
6 *
7 * Licensed under the GPL-2.
8 */
9
10#include <linux/interrupt.h>
Michael Hennerich69d900a2011-04-18 09:40:58 +020011#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>
Paul Gortmaker99c97852011-07-03 15:49:50 -040018#include <linux/module.h>
Michael Hennerich69d900a2011-04-18 09:40:58 +020019
Jonathan Cameron06458e22012-04-25 15:54:58 +010020#include <linux/iio/iio.h>
21#include <linux/iio/sysfs.h>
Lars-Peter Clausencadb6952012-06-04 11:36:19 +020022
Michael Hennerich69d900a2011-04-18 09:40:58 +020023#include "ad5791.h"
24
25static int ad5791_spi_write(struct spi_device *spi, u8 addr, u32 val)
26{
27 union {
28 u32 d32;
29 u8 d8[4];
30 } data;
31
32 data.d32 = cpu_to_be32(AD5791_CMD_WRITE |
33 AD5791_ADDR(addr) |
34 (val & AD5791_DAC_MASK));
35
36 return spi_write(spi, &data.d8[1], 3);
37}
38
39static int ad5791_spi_read(struct spi_device *spi, u8 addr, u32 *val)
40{
41 union {
42 u32 d32;
43 u8 d8[4];
44 } data[3];
45 int ret;
46 struct spi_message msg;
47 struct spi_transfer xfers[] = {
48 {
49 .tx_buf = &data[0].d8[1],
50 .bits_per_word = 8,
51 .len = 3,
52 .cs_change = 1,
53 }, {
54 .tx_buf = &data[1].d8[1],
55 .rx_buf = &data[2].d8[1],
56 .bits_per_word = 8,
57 .len = 3,
58 },
59 };
60
61 data[0].d32 = cpu_to_be32(AD5791_CMD_READ |
62 AD5791_ADDR(addr));
63 data[1].d32 = cpu_to_be32(AD5791_ADDR(AD5791_ADDR_NOOP));
64
65 spi_message_init(&msg);
66 spi_message_add_tail(&xfers[0], &msg);
67 spi_message_add_tail(&xfers[1], &msg);
68 ret = spi_sync(spi, &msg);
69
70 *val = be32_to_cpu(data[2].d32);
71
72 return ret;
73}
74
Lars-Peter Clausen4571b392012-06-04 11:36:18 +020075static const char * const ad5791_powerdown_modes[] = {
76 "6kohm_to_gnd",
77 "three_state",
Jonathan Cameronc5b99392011-09-02 17:25:19 +010078};
Michael Hennerich69d900a2011-04-18 09:40:58 +020079
Lars-Peter Clausen4571b392012-06-04 11:36:18 +020080static int ad5791_get_powerdown_mode(struct iio_dev *indio_dev,
81 const struct iio_chan_spec *chan)
Michael Hennerich69d900a2011-04-18 09:40:58 +020082{
Jonathan Cameronf5730d52011-06-27 13:07:34 +010083 struct ad5791_state *st = iio_priv(indio_dev);
Michael Hennerich69d900a2011-04-18 09:40:58 +020084
Lars-Peter Clausen4571b392012-06-04 11:36:18 +020085 return st->pwr_down_mode;
Michael Hennerich69d900a2011-04-18 09:40:58 +020086}
87
Lars-Peter Clausen4571b392012-06-04 11:36:18 +020088static int ad5791_set_powerdown_mode(struct iio_dev *indio_dev,
89 const struct iio_chan_spec *chan, unsigned int mode)
Michael Hennerich69d900a2011-04-18 09:40:58 +020090{
Jonathan Cameronf5730d52011-06-27 13:07:34 +010091 struct ad5791_state *st = iio_priv(indio_dev);
Michael Hennerich69d900a2011-04-18 09:40:58 +020092
Lars-Peter Clausen4571b392012-06-04 11:36:18 +020093 st->pwr_down_mode = mode;
Michael Hennerich69d900a2011-04-18 09:40:58 +020094
Lars-Peter Clausen4571b392012-06-04 11:36:18 +020095 return 0;
Michael Hennerich69d900a2011-04-18 09:40:58 +020096}
97
Lars-Peter Clausen4571b392012-06-04 11:36:18 +020098static const struct iio_enum ad5791_powerdown_mode_enum = {
99 .items = ad5791_powerdown_modes,
100 .num_items = ARRAY_SIZE(ad5791_powerdown_modes),
101 .get = ad5791_get_powerdown_mode,
102 .set = ad5791_set_powerdown_mode,
103};
104
105static ssize_t ad5791_read_dac_powerdown(struct iio_dev *indio_dev,
106 uintptr_t private, const struct iio_chan_spec *chan, char *buf)
Michael Hennerich69d900a2011-04-18 09:40:58 +0200107{
Jonathan Cameronf5730d52011-06-27 13:07:34 +0100108 struct ad5791_state *st = iio_priv(indio_dev);
Michael Hennerich69d900a2011-04-18 09:40:58 +0200109
110 return sprintf(buf, "%d\n", st->pwr_down);
111}
112
Lars-Peter Clausen4571b392012-06-04 11:36:18 +0200113static ssize_t ad5791_write_dac_powerdown(struct iio_dev *indio_dev,
114 uintptr_t private, const struct iio_chan_spec *chan, const char *buf,
115 size_t len)
Michael Hennerich69d900a2011-04-18 09:40:58 +0200116{
117 long readin;
118 int ret;
Jonathan Cameronf5730d52011-06-27 13:07:34 +0100119 struct ad5791_state *st = iio_priv(indio_dev);
Michael Hennerich69d900a2011-04-18 09:40:58 +0200120
121 ret = strict_strtol(buf, 10, &readin);
122 if (ret)
123 return ret;
124
125 if (readin == 0) {
126 st->pwr_down = false;
127 st->ctrl &= ~(AD5791_CTRL_OPGND | AD5791_CTRL_DACTRI);
128 } else if (readin == 1) {
129 st->pwr_down = true;
130 if (st->pwr_down_mode == AD5791_DAC_PWRDN_6K)
131 st->ctrl |= AD5791_CTRL_OPGND;
132 else if (st->pwr_down_mode == AD5791_DAC_PWRDN_3STATE)
133 st->ctrl |= AD5791_CTRL_DACTRI;
134 } else
135 ret = -EINVAL;
136
137 ret = ad5791_spi_write(st->spi, AD5791_ADDR_CTRL, st->ctrl);
138
139 return ret ? ret : len;
140}
141
Michael Hennerich69d900a2011-04-18 09:40:58 +0200142static int ad5791_get_lin_comp(unsigned int span)
143{
144 if (span <= 10000)
145 return AD5791_LINCOMP_0_10;
146 else if (span <= 12000)
147 return AD5791_LINCOMP_10_12;
148 else if (span <= 16000)
149 return AD5791_LINCOMP_12_16;
150 else if (span <= 19000)
151 return AD5791_LINCOMP_16_19;
152 else
153 return AD5791_LINCOMP_19_20;
154}
155
Michael Hennerichba1c2bb2011-04-27 17:13:58 +0200156static int ad5780_get_lin_comp(unsigned int span)
157{
158 if (span <= 10000)
159 return AD5780_LINCOMP_0_10;
160 else
161 return AD5780_LINCOMP_10_20;
162}
Michael Hennerichba1c2bb2011-04-27 17:13:58 +0200163static const struct ad5791_chip_info ad5791_chip_info_tbl[] = {
164 [ID_AD5760] = {
Michael Hennerichba1c2bb2011-04-27 17:13:58 +0200165 .get_lin_comp = ad5780_get_lin_comp,
166 },
167 [ID_AD5780] = {
Michael Hennerichba1c2bb2011-04-27 17:13:58 +0200168 .get_lin_comp = ad5780_get_lin_comp,
169 },
170 [ID_AD5781] = {
Michael Hennerichba1c2bb2011-04-27 17:13:58 +0200171 .get_lin_comp = ad5791_get_lin_comp,
172 },
173 [ID_AD5791] = {
Michael Hennerichba1c2bb2011-04-27 17:13:58 +0200174 .get_lin_comp = ad5791_get_lin_comp,
175 },
176};
177
Jonathan Cameronc5b99392011-09-02 17:25:19 +0100178static int ad5791_read_raw(struct iio_dev *indio_dev,
179 struct iio_chan_spec const *chan,
180 int *val,
181 int *val2,
182 long m)
183{
184 struct ad5791_state *st = iio_priv(indio_dev);
Lars-Peter Clausen9dc99612011-10-19 17:47:50 +0200185 u64 val64;
Jonathan Cameronc5b99392011-09-02 17:25:19 +0100186 int ret;
187
188 switch (m) {
Jonathan Cameron09f4eb42012-04-15 17:41:19 +0100189 case IIO_CHAN_INFO_RAW:
Jonathan Cameronc5b99392011-09-02 17:25:19 +0100190 ret = ad5791_spi_read(st->spi, chan->address, val);
191 if (ret)
192 return ret;
193 *val &= AD5791_DAC_MASK;
194 *val >>= chan->scan_type.shift;
Jonathan Cameronc5b99392011-09-02 17:25:19 +0100195 return IIO_VAL_INT;
Jonathan Cameronc8a9f802011-10-26 17:41:36 +0100196 case IIO_CHAN_INFO_SCALE:
Jonathan Cameronc5b99392011-09-02 17:25:19 +0100197 *val = 0;
Lars-Peter Clausen75bb23a2011-10-19 17:47:52 +0200198 *val2 = (((u64)st->vref_mv) * 1000000ULL) >> chan->scan_type.realbits;
Jonathan Cameronc5b99392011-09-02 17:25:19 +0100199 return IIO_VAL_INT_PLUS_MICRO;
Jonathan Cameronc8a9f802011-10-26 17:41:36 +0100200 case IIO_CHAN_INFO_OFFSET:
Lars-Peter Clausen9dc99612011-10-19 17:47:50 +0200201 val64 = (((u64)st->vref_neg_mv) << chan->scan_type.realbits);
202 do_div(val64, st->vref_mv);
203 *val = -val64;
204 return IIO_VAL_INT;
Jonathan Cameronc5b99392011-09-02 17:25:19 +0100205 default:
206 return -EINVAL;
207 }
208
209};
210
Lars-Peter Clausen4571b392012-06-04 11:36:18 +0200211static const struct iio_chan_spec_ext_info ad5791_ext_info[] = {
212 {
213 .name = "powerdown",
214 .shared = true,
215 .read = ad5791_read_dac_powerdown,
216 .write = ad5791_write_dac_powerdown,
217 },
218 IIO_ENUM("powerdown_mode", true, &ad5791_powerdown_mode_enum),
219 IIO_ENUM_AVAILABLE("powerdown_mode", &ad5791_powerdown_mode_enum),
220 { },
221};
222
223#define AD5791_CHAN(bits, shift) { \
224 .type = IIO_VOLTAGE, \
225 .output = 1, \
226 .indexed = 1, \
227 .address = AD5791_ADDR_DAC0, \
228 .channel = 0, \
229 .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
230 IIO_CHAN_INFO_SCALE_SHARED_BIT | \
231 IIO_CHAN_INFO_OFFSET_SHARED_BIT, \
232 .scan_type = IIO_ST('u', bits, 24, shift), \
233 .ext_info = ad5791_ext_info, \
234}
235
236static const struct iio_chan_spec ad5791_channels[] = {
237 [ID_AD5760] = AD5791_CHAN(16, 4),
238 [ID_AD5780] = AD5791_CHAN(18, 2),
239 [ID_AD5781] = AD5791_CHAN(18, 2),
240 [ID_AD5791] = AD5791_CHAN(20, 0)
241};
Jonathan Cameronc5b99392011-09-02 17:25:19 +0100242
243static int ad5791_write_raw(struct iio_dev *indio_dev,
244 struct iio_chan_spec const *chan,
245 int val,
246 int val2,
247 long mask)
248{
249 struct ad5791_state *st = iio_priv(indio_dev);
250
251 switch (mask) {
Jonathan Cameron09f4eb42012-04-15 17:41:19 +0100252 case IIO_CHAN_INFO_RAW:
Lars-Peter Clausen021c0a32011-10-19 17:47:49 +0200253 val &= AD5791_RES_MASK(chan->scan_type.realbits);
Jonathan Cameronc5b99392011-09-02 17:25:19 +0100254 val <<= chan->scan_type.shift;
255
256 return ad5791_spi_write(st->spi, chan->address, val);
257
258 default:
259 return -EINVAL;
260 }
261}
262
Jonathan Cameron6fe81352011-05-18 14:42:37 +0100263static const struct iio_info ad5791_info = {
Jonathan Cameronc5b99392011-09-02 17:25:19 +0100264 .read_raw = &ad5791_read_raw,
265 .write_raw = &ad5791_write_raw,
Jonathan Cameron6fe81352011-05-18 14:42:37 +0100266 .driver_module = THIS_MODULE,
267};
268
Michael Hennerich69d900a2011-04-18 09:40:58 +0200269static int __devinit ad5791_probe(struct spi_device *spi)
270{
271 struct ad5791_platform_data *pdata = spi->dev.platform_data;
Jonathan Cameronf5730d52011-06-27 13:07:34 +0100272 struct iio_dev *indio_dev;
Michael Hennerich69d900a2011-04-18 09:40:58 +0200273 struct ad5791_state *st;
274 int ret, pos_voltage_uv = 0, neg_voltage_uv = 0;
275
Lars-Peter Clausen7cbb7532012-04-26 13:35:01 +0200276 indio_dev = iio_device_alloc(sizeof(*st));
Jonathan Cameronf5730d52011-06-27 13:07:34 +0100277 if (indio_dev == NULL) {
278 ret = -ENOMEM;
Jonathan Cameron26a54792011-08-30 12:41:19 +0100279 goto error_ret;
Jonathan Cameronf5730d52011-06-27 13:07:34 +0100280 }
281 st = iio_priv(indio_dev);
Jonathan Cameron26a54792011-08-30 12:41:19 +0100282 st->reg_vdd = regulator_get(&spi->dev, "vdd");
283 if (!IS_ERR(st->reg_vdd)) {
284 ret = regulator_enable(st->reg_vdd);
285 if (ret)
286 goto error_put_reg_pos;
287
288 pos_voltage_uv = regulator_get_voltage(st->reg_vdd);
289 }
290
291 st->reg_vss = regulator_get(&spi->dev, "vss");
292 if (!IS_ERR(st->reg_vss)) {
293 ret = regulator_enable(st->reg_vss);
294 if (ret)
295 goto error_put_reg_neg;
296
297 neg_voltage_uv = regulator_get_voltage(st->reg_vss);
298 }
299
Jonathan Cameronf5730d52011-06-27 13:07:34 +0100300 st->pwr_down = true;
301 st->spi = spi;
302
Lars-Peter Clausen9dc99612011-10-19 17:47:50 +0200303 if (!IS_ERR(st->reg_vss) && !IS_ERR(st->reg_vdd)) {
304 st->vref_mv = (pos_voltage_uv + neg_voltage_uv) / 1000;
305 st->vref_neg_mv = neg_voltage_uv / 1000;
306 } else if (pdata) {
307 st->vref_mv = pdata->vref_pos_mv + pdata->vref_neg_mv;
308 st->vref_neg_mv = pdata->vref_neg_mv;
309 } else {
Michael Hennerich69d900a2011-04-18 09:40:58 +0200310 dev_warn(&spi->dev, "reference voltage unspecified\n");
Lars-Peter Clausen9dc99612011-10-19 17:47:50 +0200311 }
Michael Hennerich69d900a2011-04-18 09:40:58 +0200312
313 ret = ad5791_spi_write(spi, AD5791_ADDR_SW_CTRL, AD5791_SWCTRL_RESET);
314 if (ret)
Jonathan Cameron26a54792011-08-30 12:41:19 +0100315 goto error_disable_reg_neg;
Michael Hennerich69d900a2011-04-18 09:40:58 +0200316
Jonathan Cameronc5b99392011-09-02 17:25:19 +0100317 st->chip_info = &ad5791_chip_info_tbl[spi_get_device_id(spi)
318 ->driver_data];
Michael Hennerich69d900a2011-04-18 09:40:58 +0200319
320
Michael Hennerichba1c2bb2011-04-27 17:13:58 +0200321 st->ctrl = AD5761_CTRL_LINCOMP(st->chip_info->get_lin_comp(st->vref_mv))
322 | ((pdata && pdata->use_rbuf_gain2) ? 0 : AD5791_CTRL_RBUF) |
Michael Hennerich69d900a2011-04-18 09:40:58 +0200323 AD5791_CTRL_BIN2SC;
324
325 ret = ad5791_spi_write(spi, AD5791_ADDR_CTRL, st->ctrl |
326 AD5791_CTRL_OPGND | AD5791_CTRL_DACTRI);
327 if (ret)
Jonathan Cameron26a54792011-08-30 12:41:19 +0100328 goto error_disable_reg_neg;
Michael Hennerich69d900a2011-04-18 09:40:58 +0200329
Jonathan Cameronf5730d52011-06-27 13:07:34 +0100330 spi_set_drvdata(spi, indio_dev);
331 indio_dev->dev.parent = &spi->dev;
332 indio_dev->info = &ad5791_info;
333 indio_dev->modes = INDIO_DIRECT_MODE;
Jonathan Cameronc5b99392011-09-02 17:25:19 +0100334 indio_dev->channels
335 = &ad5791_channels[spi_get_device_id(spi)->driver_data];
336 indio_dev->num_channels = 1;
337 indio_dev->name = spi_get_device_id(st->spi)->name;
Jonathan Cameronf5730d52011-06-27 13:07:34 +0100338 ret = iio_device_register(indio_dev);
Michael Hennerich69d900a2011-04-18 09:40:58 +0200339 if (ret)
Jonathan Cameron26a54792011-08-30 12:41:19 +0100340 goto error_disable_reg_neg;
Michael Hennerich69d900a2011-04-18 09:40:58 +0200341
342 return 0;
343
Michael Hennerich69d900a2011-04-18 09:40:58 +0200344error_disable_reg_neg:
Jonathan Cameron26a54792011-08-30 12:41:19 +0100345 if (!IS_ERR(st->reg_vss))
346 regulator_disable(st->reg_vss);
Michael Hennerich69d900a2011-04-18 09:40:58 +0200347error_put_reg_neg:
Jonathan Cameron26a54792011-08-30 12:41:19 +0100348 if (!IS_ERR(st->reg_vss))
349 regulator_put(st->reg_vss);
Michael Hennerich69d900a2011-04-18 09:40:58 +0200350
Jonathan Cameron26a54792011-08-30 12:41:19 +0100351 if (!IS_ERR(st->reg_vdd))
352 regulator_disable(st->reg_vdd);
Michael Hennerich69d900a2011-04-18 09:40:58 +0200353error_put_reg_pos:
Jonathan Cameron26a54792011-08-30 12:41:19 +0100354 if (!IS_ERR(st->reg_vdd))
355 regulator_put(st->reg_vdd);
Lars-Peter Clausen7cbb7532012-04-26 13:35:01 +0200356 iio_device_free(indio_dev);
Jonathan Cameron26a54792011-08-30 12:41:19 +0100357error_ret:
Michael Hennerich69d900a2011-04-18 09:40:58 +0200358
Michael Hennerich69d900a2011-04-18 09:40:58 +0200359 return ret;
360}
361
362static int __devexit ad5791_remove(struct spi_device *spi)
363{
Jonathan Cameronf5730d52011-06-27 13:07:34 +0100364 struct iio_dev *indio_dev = spi_get_drvdata(spi);
365 struct ad5791_state *st = iio_priv(indio_dev);
Michael Hennerich69d900a2011-04-18 09:40:58 +0200366
Jonathan Camerond2fffd62011-10-14 14:46:58 +0100367 iio_device_unregister(indio_dev);
Michael Hennerich69d900a2011-04-18 09:40:58 +0200368 if (!IS_ERR(st->reg_vdd)) {
Jonathan Cameron26a54792011-08-30 12:41:19 +0100369 regulator_disable(st->reg_vdd);
370 regulator_put(st->reg_vdd);
Michael Hennerich69d900a2011-04-18 09:40:58 +0200371 }
372
373 if (!IS_ERR(st->reg_vss)) {
Jonathan Cameron26a54792011-08-30 12:41:19 +0100374 regulator_disable(st->reg_vss);
375 regulator_put(st->reg_vss);
Michael Hennerich69d900a2011-04-18 09:40:58 +0200376 }
Lars-Peter Clausen7cbb7532012-04-26 13:35:01 +0200377 iio_device_free(indio_dev);
Jonathan Cameron26d25ae2011-09-02 17:14:40 +0100378
Michael Hennerich69d900a2011-04-18 09:40:58 +0200379 return 0;
380}
381
382static const struct spi_device_id ad5791_id[] = {
Michael Hennerichba1c2bb2011-04-27 17:13:58 +0200383 {"ad5760", ID_AD5760},
384 {"ad5780", ID_AD5780},
Michael Hennerich69d900a2011-04-18 09:40:58 +0200385 {"ad5781", ID_AD5781},
Lars-Peter Clausen9d41c5b2011-12-09 17:12:42 +0100386 {"ad5790", ID_AD5791},
Michael Hennerichba1c2bb2011-04-27 17:13:58 +0200387 {"ad5791", ID_AD5791},
Michael Hennerich69d900a2011-04-18 09:40:58 +0200388 {}
389};
Lars-Peter Clausen55e43902011-11-16 08:53:31 +0100390MODULE_DEVICE_TABLE(spi, ad5791_id);
Michael Hennerich69d900a2011-04-18 09:40:58 +0200391
392static struct spi_driver ad5791_driver = {
393 .driver = {
394 .name = "ad5791",
395 .owner = THIS_MODULE,
396 },
397 .probe = ad5791_probe,
398 .remove = __devexit_p(ad5791_remove),
399 .id_table = ad5791_id,
400};
Lars-Peter Clausenae6ae6f2011-11-16 10:13:39 +0100401module_spi_driver(ad5791_driver);
Michael Hennerich69d900a2011-04-18 09:40:58 +0200402
403MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
Lars-Peter Clausen9d41c5b2011-12-09 17:12:42 +0100404MODULE_DESCRIPTION("Analog Devices AD5760/AD5780/AD5781/AD5790/AD5791 DAC");
Michael Hennerich69d900a2011-04-18 09:40:58 +0200405MODULE_LICENSE("GPL v2");