aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iio
diff options
context:
space:
mode:
authorLars-Peter Clausen <lars@metafoo.de>2013-06-11 12:56:00 -0400
committerJonathan Cameron <jic23@kernel.org>2013-06-11 15:25:58 -0400
commitf83478240e742efe1103110c28d48cc2b4dcee5c (patch)
tree0a44961fa6e7c54e2d08610a2137d2d04e0ba21d /drivers/iio
parente764df67963940b4123325710536a9471d1e24ae (diff)
iio:dac: Add support for the AD7303
This patch adds support for the AD7303. The AD7303 is a simple 2 channel 8 bit DAC with an SPI interface. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
Diffstat (limited to 'drivers/iio')
-rw-r--r--drivers/iio/dac/Kconfig10
-rw-r--r--drivers/iio/dac/Makefile1
-rw-r--r--drivers/iio/dac/ad7303.c315
3 files changed, 326 insertions, 0 deletions
diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig
index b61160bd935e..c9c33ce32d3a 100644
--- a/drivers/iio/dac/Kconfig
+++ b/drivers/iio/dac/Kconfig
@@ -130,6 +130,16 @@ config AD5686
130 To compile this driver as a module, choose M here: the 130 To compile this driver as a module, choose M here: the
131 module will be called ad5686. 131 module will be called ad5686.
132 132
133config AD7303
134 tristate "Analog Devices Analog Devices AD7303 DAC driver"
135 depends on SPI
136 help
137 Say yes here to build support for Analog Devices AD7303 Digital to Analog
138 Converters (DAC).
139
140 To compile this driver as module choose M here: the module will be called
141 ad7303.
142
133config MAX517 143config MAX517
134 tristate "Maxim MAX517/518/519 DAC driver" 144 tristate "Maxim MAX517/518/519 DAC driver"
135 depends on I2C 145 depends on I2C
diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile
index 5b528ebb3343..c8d7ab6bff01 100644
--- a/drivers/iio/dac/Makefile
+++ b/drivers/iio/dac/Makefile
@@ -14,5 +14,6 @@ obj-$(CONFIG_AD5755) += ad5755.o
14obj-$(CONFIG_AD5764) += ad5764.o 14obj-$(CONFIG_AD5764) += ad5764.o
15obj-$(CONFIG_AD5791) += ad5791.o 15obj-$(CONFIG_AD5791) += ad5791.o
16obj-$(CONFIG_AD5686) += ad5686.o 16obj-$(CONFIG_AD5686) += ad5686.o
17obj-$(CONFIG_AD7303) += ad7303.o
17obj-$(CONFIG_MAX517) += max517.o 18obj-$(CONFIG_MAX517) += max517.o
18obj-$(CONFIG_MCP4725) += mcp4725.o 19obj-$(CONFIG_MCP4725) += mcp4725.o
diff --git a/drivers/iio/dac/ad7303.c b/drivers/iio/dac/ad7303.c
new file mode 100644
index 000000000000..85aeef60dc5f
--- /dev/null
+++ b/drivers/iio/dac/ad7303.c
@@ -0,0 +1,315 @@
1/*
2 * AD7303 Digital to analog converters driver
3 *
4 * Copyright 2013 Analog Devices Inc.
5 *
6 * Licensed under the GPL-2.
7 */
8
9#include <linux/err.h>
10#include <linux/module.h>
11#include <linux/kernel.h>
12#include <linux/spi/spi.h>
13#include <linux/slab.h>
14#include <linux/sysfs.h>
15#include <linux/regulator/consumer.h>
16#include <linux/of.h>
17
18#include <linux/iio/iio.h>
19#include <linux/iio/sysfs.h>
20
21#include <linux/platform_data/ad7303.h>
22
23#define AD7303_CFG_EXTERNAL_VREF BIT(15)
24#define AD7303_CFG_POWER_DOWN(ch) BIT(11 + (ch))
25#define AD7303_CFG_ADDR_OFFSET 10
26
27#define AD7303_CMD_UPDATE_DAC (0x3 << 8)
28
29/**
30 * struct ad7303_state - driver instance specific data
31 * @spi: the device for this driver instance
32 * @config: cached config register value
33 * @dac_cache: current DAC raw value (chip does not support readback)
34 * @data: spi transfer buffer
35 */
36
37struct ad7303_state {
38 struct spi_device *spi;
39 uint16_t config;
40 uint8_t dac_cache[2];
41
42 struct regulator *vdd_reg;
43 struct regulator *vref_reg;
44
45 /*
46 * DMA (thus cache coherency maintenance) requires the
47 * transfer buffers to live in their own cache lines.
48 */
49 __be16 data ____cacheline_aligned;
50};
51
52static int ad7303_write(struct ad7303_state *st, unsigned int chan,
53 uint8_t val)
54{
55 st->data = cpu_to_be16(AD7303_CMD_UPDATE_DAC |
56 (chan << AD7303_CFG_ADDR_OFFSET) |
57 st->config | val);
58
59 return spi_write(st->spi, &st->data, sizeof(st->data));
60}
61
62static ssize_t ad7303_read_dac_powerdown(struct iio_dev *indio_dev,
63 uintptr_t private, const struct iio_chan_spec *chan, char *buf)
64{
65 struct ad7303_state *st = iio_priv(indio_dev);
66
67 return sprintf(buf, "%d\n", (bool)(st->config &
68 AD7303_CFG_POWER_DOWN(chan->channel)));
69}
70
71static ssize_t ad7303_write_dac_powerdown(struct iio_dev *indio_dev,
72 uintptr_t private, const struct iio_chan_spec *chan, const char *buf,
73 size_t len)
74{
75 struct ad7303_state *st = iio_priv(indio_dev);
76 bool pwr_down;
77 int ret;
78
79 ret = strtobool(buf, &pwr_down);
80 if (ret)
81 return ret;
82
83 mutex_lock(&indio_dev->mlock);
84
85 if (pwr_down)
86 st->config |= AD7303_CFG_POWER_DOWN(chan->channel);
87 else
88 st->config &= ~AD7303_CFG_POWER_DOWN(chan->channel);
89
90 /* There is no noop cmd which allows us to only update the powerdown
91 * mode, so just write one of the DAC channels again */
92 ad7303_write(st, chan->channel, st->dac_cache[chan->channel]);
93
94 mutex_unlock(&indio_dev->mlock);
95 return ret ? ret : len;
96}
97
98static int ad7303_get_vref(struct ad7303_state *st,
99 struct iio_chan_spec const *chan)
100{
101 int ret;
102
103 if (st->config & AD7303_CFG_EXTERNAL_VREF)
104 return regulator_get_voltage(st->vref_reg);
105
106 ret = regulator_get_voltage(st->vdd_reg);
107 if (ret < 0)
108 return ret;
109 return ret / 2;
110}
111
112static int ad7303_read_raw(struct iio_dev *indio_dev,
113 struct iio_chan_spec const *chan, int *val, int *val2, long info)
114{
115 struct ad7303_state *st = iio_priv(indio_dev);
116 int vref_uv;
117
118 switch (info) {
119 case IIO_CHAN_INFO_RAW:
120 *val = st->dac_cache[chan->channel];
121 return IIO_VAL_INT;
122 case IIO_CHAN_INFO_SCALE:
123 vref_uv = ad7303_get_vref(st, chan);
124 if (vref_uv < 0)
125 return vref_uv;
126
127 *val = 2 * vref_uv / 1000;
128 *val2 = chan->scan_type.realbits;
129
130 return IIO_VAL_FRACTIONAL_LOG2;
131 default:
132 break;
133 }
134 return -EINVAL;
135}
136
137static int ad7303_write_raw(struct iio_dev *indio_dev,
138 struct iio_chan_spec const *chan, int val, int val2, long mask)
139{
140 struct ad7303_state *st = iio_priv(indio_dev);
141 int ret;
142
143 switch (mask) {
144 case IIO_CHAN_INFO_RAW:
145 if (val >= (1 << chan->scan_type.realbits) || val < 0)
146 return -EINVAL;
147
148 mutex_lock(&indio_dev->mlock);
149 ret = ad7303_write(st, chan->address, val);
150 if (ret == 0)
151 st->dac_cache[chan->channel] = val;
152 mutex_unlock(&indio_dev->mlock);
153 break;
154 default:
155 ret = -EINVAL;
156 }
157
158 return ret;
159}
160
161static const struct iio_info ad7303_info = {
162 .read_raw = ad7303_read_raw,
163 .write_raw = ad7303_write_raw,
164 .driver_module = THIS_MODULE,
165};
166
167static const struct iio_chan_spec_ext_info ad7303_ext_info[] = {
168 {
169 .name = "powerdown",
170 .read = ad7303_read_dac_powerdown,
171 .write = ad7303_write_dac_powerdown,
172 },
173 { },
174};
175
176#define AD7303_CHANNEL(chan) { \
177 .type = IIO_VOLTAGE, \
178 .indexed = 1, \
179 .output = 1, \
180 .channel = (chan), \
181 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
182 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
183 .address = (chan), \
184 .scan_type = { \
185 .sign = 'u', \
186 .realbits = '8', \
187 .storagebits = '8', \
188 .shift = '0', \
189 }, \
190 .ext_info = ad7303_ext_info, \
191}
192
193static const struct iio_chan_spec ad7303_channels[] = {
194 AD7303_CHANNEL(0),
195 AD7303_CHANNEL(1),
196};
197
198static int ad7303_probe(struct spi_device *spi)
199{
200 const struct spi_device_id *id = spi_get_device_id(spi);
201 struct iio_dev *indio_dev;
202 struct ad7303_state *st;
203 bool ext_ref;
204 int ret;
205
206 indio_dev = iio_device_alloc(sizeof(*st));
207 if (indio_dev == NULL)
208 return -ENOMEM;
209
210 st = iio_priv(indio_dev);
211 spi_set_drvdata(spi, indio_dev);
212
213 st->spi = spi;
214
215 st->vdd_reg = regulator_get(&spi->dev, "Vdd");
216 if (IS_ERR(st->vdd_reg)) {
217 ret = PTR_ERR(st->vdd_reg);
218 goto err_free;
219 }
220
221 ret = regulator_enable(st->vdd_reg);
222 if (ret)
223 goto err_put_vdd_reg;
224
225 if (spi->dev.of_node) {
226 ext_ref = of_property_read_bool(spi->dev.of_node,
227 "REF-supply");
228 } else {
229 struct ad7303_platform_data *pdata = spi->dev.platform_data;
230 if (pdata && pdata->use_external_ref)
231 ext_ref = true;
232 else
233 ext_ref = false;
234 }
235
236 if (ext_ref) {
237 st->vref_reg = regulator_get(&spi->dev, "REF");
238 if (IS_ERR(st->vref_reg))
239 goto err_disable_vdd_reg;
240
241 ret = regulator_enable(st->vref_reg);
242 if (ret)
243 goto err_put_vref_reg;
244
245 st->config |= AD7303_CFG_EXTERNAL_VREF;
246 }
247
248 indio_dev->dev.parent = &spi->dev;
249 indio_dev->name = id->name;
250 indio_dev->info = &ad7303_info;
251 indio_dev->modes = INDIO_DIRECT_MODE;
252 indio_dev->channels = ad7303_channels;
253 indio_dev->num_channels = ARRAY_SIZE(ad7303_channels);
254
255 ret = iio_device_register(indio_dev);
256 if (ret)
257 goto err_disable_vref_reg;
258
259 return 0;
260
261err_disable_vref_reg:
262 if (st->vref_reg)
263 regulator_disable(st->vref_reg);
264err_put_vref_reg:
265 if (st->vref_reg)
266 regulator_put(st->vref_reg);
267err_disable_vdd_reg:
268 regulator_disable(st->vdd_reg);
269err_put_vdd_reg:
270 regulator_put(st->vdd_reg);
271err_free:
272 iio_device_free(indio_dev);
273
274 return ret;
275}
276
277static int ad7303_remove(struct spi_device *spi)
278{
279 struct iio_dev *indio_dev = spi_get_drvdata(spi);
280 struct ad7303_state *st = iio_priv(indio_dev);
281
282 iio_device_unregister(indio_dev);
283
284 if (st->vref_reg) {
285 regulator_disable(st->vref_reg);
286 regulator_put(st->vref_reg);
287 }
288 regulator_disable(st->vdd_reg);
289 regulator_put(st->vdd_reg);
290
291 iio_device_free(indio_dev);
292
293 return 0;
294}
295
296static const struct spi_device_id ad7303_spi_ids[] = {
297 { "ad7303", 0 },
298 {}
299};
300MODULE_DEVICE_TABLE(spi, ad7303_spi_ids);
301
302static struct spi_driver ad7303_driver = {
303 .driver = {
304 .name = "ad7303",
305 .owner = THIS_MODULE,
306 },
307 .probe = ad7303_probe,
308 .remove = ad7303_remove,
309 .id_table = ad7303_spi_ids,
310};
311module_spi_driver(ad7303_driver);
312
313MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
314MODULE_DESCRIPTION("Analog Devices AD7303 DAC driver");
315MODULE_LICENSE("GPL v2");