]>
Commit | Line | Data |
---|---|---|
8341dc04 LPC |
1 | /* |
2 | * AD5415, AD5426, AD5429, AD5432, AD5439, AD5443, AD5449 Digital to Analog | |
3 | * Converter driver. | |
4 | * | |
5 | * Copyright 2012 Analog Devices Inc. | |
6 | * Author: Lars-Peter Clausen <[email protected]> | |
7 | * | |
8 | * Licensed under the GPL-2. | |
9 | */ | |
10 | ||
11 | #include <linux/device.h> | |
12 | #include <linux/err.h> | |
13 | #include <linux/module.h> | |
14 | #include <linux/kernel.h> | |
15 | #include <linux/spi/spi.h> | |
16 | #include <linux/slab.h> | |
17 | #include <linux/sysfs.h> | |
18 | #include <linux/regulator/consumer.h> | |
19 | #include <asm/unaligned.h> | |
20 | ||
21 | #include <linux/iio/iio.h> | |
22 | #include <linux/iio/sysfs.h> | |
23 | ||
24 | #include <linux/platform_data/ad5449.h> | |
25 | ||
26 | #define AD5449_MAX_CHANNELS 2 | |
27 | #define AD5449_MAX_VREFS 2 | |
28 | ||
29 | #define AD5449_CMD_NOOP 0x0 | |
30 | #define AD5449_CMD_LOAD_AND_UPDATE(x) (0x1 + (x) * 3) | |
31 | #define AD5449_CMD_READ(x) (0x2 + (x) * 3) | |
32 | #define AD5449_CMD_LOAD(x) (0x3 + (x) * 3) | |
33 | #define AD5449_CMD_CTRL 13 | |
34 | ||
35 | #define AD5449_CTRL_SDO_OFFSET 10 | |
36 | #define AD5449_CTRL_DAISY_CHAIN BIT(9) | |
37 | #define AD5449_CTRL_HCLR_TO_MIDSCALE BIT(8) | |
38 | #define AD5449_CTRL_SAMPLE_RISING BIT(7) | |
39 | ||
40 | /** | |
41 | * struct ad5449_chip_info - chip specific information | |
42 | * @channels: Channel specification | |
43 | * @num_channels: Number of channels | |
44 | * @has_ctrl: Chip has a control register | |
45 | */ | |
46 | struct ad5449_chip_info { | |
47 | const struct iio_chan_spec *channels; | |
48 | unsigned int num_channels; | |
49 | bool has_ctrl; | |
50 | }; | |
51 | ||
52 | /** | |
53 | * struct ad5449 - driver instance specific data | |
54 | * @spi: the SPI device for this driver instance | |
55 | * @chip_info: chip model specific constants, available modes etc | |
56 | * @vref_reg: vref supply regulators | |
57 | * @has_sdo: whether the SDO line is connected | |
58 | * @dac_cache: Cache for the DAC values | |
59 | * @data: spi transfer buffers | |
60 | */ | |
61 | struct ad5449 { | |
62 | struct spi_device *spi; | |
63 | const struct ad5449_chip_info *chip_info; | |
64 | struct regulator_bulk_data vref_reg[AD5449_MAX_VREFS]; | |
65 | ||
66 | bool has_sdo; | |
67 | uint16_t dac_cache[AD5449_MAX_CHANNELS]; | |
68 | ||
69 | /* | |
70 | * DMA (thus cache coherency maintenance) requires the | |
71 | * transfer buffers to live in their own cache lines. | |
72 | */ | |
73 | __be16 data[2] ____cacheline_aligned; | |
74 | }; | |
75 | ||
76 | enum ad5449_type { | |
77 | ID_AD5426, | |
78 | ID_AD5429, | |
79 | ID_AD5432, | |
80 | ID_AD5439, | |
81 | ID_AD5443, | |
82 | ID_AD5449, | |
83 | }; | |
84 | ||
85 | static int ad5449_write(struct iio_dev *indio_dev, unsigned int addr, | |
86 | unsigned int val) | |
87 | { | |
88 | struct ad5449 *st = iio_priv(indio_dev); | |
89 | int ret; | |
90 | ||
91 | mutex_lock(&indio_dev->mlock); | |
92 | st->data[0] = cpu_to_be16((addr << 12) | val); | |
93 | ret = spi_write(st->spi, st->data, 2); | |
94 | mutex_unlock(&indio_dev->mlock); | |
95 | ||
96 | return ret; | |
97 | } | |
98 | ||
99 | static int ad5449_read(struct iio_dev *indio_dev, unsigned int addr, | |
100 | unsigned int *val) | |
101 | { | |
102 | struct ad5449 *st = iio_priv(indio_dev); | |
103 | int ret; | |
8341dc04 LPC |
104 | struct spi_transfer t[] = { |
105 | { | |
106 | .tx_buf = &st->data[0], | |
107 | .len = 2, | |
108 | .cs_change = 1, | |
109 | }, { | |
110 | .tx_buf = &st->data[1], | |
111 | .rx_buf = &st->data[1], | |
112 | .len = 2, | |
113 | }, | |
114 | }; | |
115 | ||
8341dc04 LPC |
116 | mutex_lock(&indio_dev->mlock); |
117 | st->data[0] = cpu_to_be16(addr << 12); | |
118 | st->data[1] = cpu_to_be16(AD5449_CMD_NOOP); | |
119 | ||
66a18916 | 120 | ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t)); |
8341dc04 | 121 | if (ret < 0) |
0c88d23c | 122 | goto out_unlock; |
8341dc04 LPC |
123 | |
124 | *val = be16_to_cpu(st->data[1]); | |
8341dc04 | 125 | |
0c88d23c DC |
126 | out_unlock: |
127 | mutex_unlock(&indio_dev->mlock); | |
128 | return ret; | |
8341dc04 LPC |
129 | } |
130 | ||
131 | static int ad5449_read_raw(struct iio_dev *indio_dev, | |
132 | struct iio_chan_spec const *chan, int *val, int *val2, long info) | |
133 | { | |
134 | struct ad5449 *st = iio_priv(indio_dev); | |
135 | struct regulator_bulk_data *reg; | |
136 | int scale_uv; | |
137 | int ret; | |
138 | ||
139 | switch (info) { | |
140 | case IIO_CHAN_INFO_RAW: | |
141 | if (st->has_sdo) { | |
142 | ret = ad5449_read(indio_dev, | |
143 | AD5449_CMD_READ(chan->address), val); | |
144 | if (ret) | |
145 | return ret; | |
146 | *val &= 0xfff; | |
147 | } else { | |
148 | *val = st->dac_cache[chan->address]; | |
149 | } | |
150 | ||
151 | return IIO_VAL_INT; | |
152 | case IIO_CHAN_INFO_SCALE: | |
153 | reg = &st->vref_reg[chan->channel]; | |
154 | scale_uv = regulator_get_voltage(reg->consumer); | |
155 | if (scale_uv < 0) | |
156 | return scale_uv; | |
157 | ||
158 | *val = scale_uv / 1000; | |
159 | *val2 = chan->scan_type.realbits; | |
160 | ||
161 | return IIO_VAL_FRACTIONAL_LOG2; | |
162 | default: | |
163 | break; | |
164 | } | |
165 | ||
166 | return -EINVAL; | |
167 | } | |
168 | ||
169 | static int ad5449_write_raw(struct iio_dev *indio_dev, | |
170 | struct iio_chan_spec const *chan, int val, int val2, long info) | |
171 | { | |
172 | struct ad5449 *st = iio_priv(indio_dev); | |
173 | int ret; | |
174 | ||
175 | switch (info) { | |
176 | case IIO_CHAN_INFO_RAW: | |
177 | if (val < 0 || val >= (1 << chan->scan_type.realbits)) | |
178 | return -EINVAL; | |
179 | ||
180 | ret = ad5449_write(indio_dev, | |
181 | AD5449_CMD_LOAD_AND_UPDATE(chan->address), | |
182 | val << chan->scan_type.shift); | |
183 | if (ret == 0) | |
184 | st->dac_cache[chan->address] = val; | |
185 | break; | |
186 | default: | |
187 | ret = -EINVAL; | |
188 | } | |
189 | ||
190 | return ret; | |
191 | } | |
192 | ||
193 | static const struct iio_info ad5449_info = { | |
194 | .read_raw = ad5449_read_raw, | |
195 | .write_raw = ad5449_write_raw, | |
8341dc04 LPC |
196 | }; |
197 | ||
198 | #define AD5449_CHANNEL(chan, bits) { \ | |
199 | .type = IIO_VOLTAGE, \ | |
200 | .indexed = 1, \ | |
201 | .output = 1, \ | |
202 | .channel = (chan), \ | |
f8c62713 JC |
203 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ |
204 | BIT(IIO_CHAN_INFO_SCALE), \ | |
8341dc04 | 205 | .address = (chan), \ |
3d42e148 JC |
206 | .scan_type = { \ |
207 | .sign = 'u', \ | |
208 | .realbits = (bits), \ | |
209 | .storagebits = 16, \ | |
210 | .shift = 12 - (bits), \ | |
211 | }, \ | |
8341dc04 LPC |
212 | } |
213 | ||
214 | #define DECLARE_AD5449_CHANNELS(name, bits) \ | |
215 | const struct iio_chan_spec name[] = { \ | |
216 | AD5449_CHANNEL(0, bits), \ | |
217 | AD5449_CHANNEL(1, bits), \ | |
218 | } | |
219 | ||
220 | static DECLARE_AD5449_CHANNELS(ad5429_channels, 8); | |
221 | static DECLARE_AD5449_CHANNELS(ad5439_channels, 10); | |
222 | static DECLARE_AD5449_CHANNELS(ad5449_channels, 12); | |
223 | ||
224 | static const struct ad5449_chip_info ad5449_chip_info[] = { | |
225 | [ID_AD5426] = { | |
226 | .channels = ad5429_channels, | |
227 | .num_channels = 1, | |
228 | .has_ctrl = false, | |
229 | }, | |
230 | [ID_AD5429] = { | |
231 | .channels = ad5429_channels, | |
232 | .num_channels = 2, | |
233 | .has_ctrl = true, | |
234 | }, | |
235 | [ID_AD5432] = { | |
236 | .channels = ad5439_channels, | |
237 | .num_channels = 1, | |
238 | .has_ctrl = false, | |
239 | }, | |
240 | [ID_AD5439] = { | |
241 | .channels = ad5439_channels, | |
242 | .num_channels = 2, | |
243 | .has_ctrl = true, | |
244 | }, | |
245 | [ID_AD5443] = { | |
246 | .channels = ad5449_channels, | |
247 | .num_channels = 1, | |
248 | .has_ctrl = false, | |
249 | }, | |
250 | [ID_AD5449] = { | |
251 | .channels = ad5449_channels, | |
252 | .num_channels = 2, | |
253 | .has_ctrl = true, | |
254 | }, | |
255 | }; | |
256 | ||
257 | static const char *ad5449_vref_name(struct ad5449 *st, int n) | |
258 | { | |
259 | if (st->chip_info->num_channels == 1) | |
260 | return "VREF"; | |
261 | ||
262 | if (n == 0) | |
263 | return "VREFA"; | |
264 | else | |
265 | return "VREFB"; | |
266 | } | |
267 | ||
fc52692c | 268 | static int ad5449_spi_probe(struct spi_device *spi) |
8341dc04 LPC |
269 | { |
270 | struct ad5449_platform_data *pdata = spi->dev.platform_data; | |
271 | const struct spi_device_id *id = spi_get_device_id(spi); | |
272 | struct iio_dev *indio_dev; | |
273 | struct ad5449 *st; | |
274 | unsigned int i; | |
275 | int ret; | |
276 | ||
cd5e5785 | 277 | indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); |
8341dc04 LPC |
278 | if (indio_dev == NULL) |
279 | return -ENOMEM; | |
280 | ||
281 | st = iio_priv(indio_dev); | |
282 | spi_set_drvdata(spi, indio_dev); | |
283 | ||
284 | st->chip_info = &ad5449_chip_info[id->driver_data]; | |
285 | st->spi = spi; | |
286 | ||
287 | for (i = 0; i < st->chip_info->num_channels; ++i) | |
288 | st->vref_reg[i].supply = ad5449_vref_name(st, i); | |
289 | ||
cd5e5785 | 290 | ret = devm_regulator_bulk_get(&spi->dev, st->chip_info->num_channels, |
8341dc04 LPC |
291 | st->vref_reg); |
292 | if (ret) | |
cd5e5785 | 293 | return ret; |
8341dc04 LPC |
294 | |
295 | ret = regulator_bulk_enable(st->chip_info->num_channels, st->vref_reg); | |
296 | if (ret) | |
cd5e5785 | 297 | return ret; |
8341dc04 LPC |
298 | |
299 | indio_dev->dev.parent = &spi->dev; | |
300 | indio_dev->name = id->name; | |
301 | indio_dev->info = &ad5449_info; | |
302 | indio_dev->modes = INDIO_DIRECT_MODE; | |
303 | indio_dev->channels = st->chip_info->channels; | |
304 | indio_dev->num_channels = st->chip_info->num_channels; | |
305 | ||
306 | if (st->chip_info->has_ctrl) { | |
307 | unsigned int ctrl = 0x00; | |
308 | if (pdata) { | |
309 | if (pdata->hardware_clear_to_midscale) | |
310 | ctrl |= AD5449_CTRL_HCLR_TO_MIDSCALE; | |
311 | ctrl |= pdata->sdo_mode << AD5449_CTRL_SDO_OFFSET; | |
312 | st->has_sdo = pdata->sdo_mode != AD5449_SDO_DISABLED; | |
313 | } else { | |
314 | st->has_sdo = true; | |
315 | } | |
316 | ad5449_write(indio_dev, AD5449_CMD_CTRL, ctrl); | |
317 | } | |
318 | ||
319 | ret = iio_device_register(indio_dev); | |
320 | if (ret) | |
321 | goto error_disable_reg; | |
322 | ||
323 | return 0; | |
324 | ||
325 | error_disable_reg: | |
326 | regulator_bulk_disable(st->chip_info->num_channels, st->vref_reg); | |
8341dc04 LPC |
327 | |
328 | return ret; | |
329 | } | |
330 | ||
fc52692c | 331 | static int ad5449_spi_remove(struct spi_device *spi) |
8341dc04 LPC |
332 | { |
333 | struct iio_dev *indio_dev = spi_get_drvdata(spi); | |
334 | struct ad5449 *st = iio_priv(indio_dev); | |
335 | ||
336 | iio_device_unregister(indio_dev); | |
337 | ||
338 | regulator_bulk_disable(st->chip_info->num_channels, st->vref_reg); | |
8341dc04 LPC |
339 | |
340 | return 0; | |
341 | } | |
342 | ||
343 | static const struct spi_device_id ad5449_spi_ids[] = { | |
344 | { "ad5415", ID_AD5449 }, | |
345 | { "ad5426", ID_AD5426 }, | |
346 | { "ad5429", ID_AD5429 }, | |
347 | { "ad5432", ID_AD5432 }, | |
348 | { "ad5439", ID_AD5439 }, | |
349 | { "ad5443", ID_AD5443 }, | |
350 | { "ad5449", ID_AD5449 }, | |
351 | {} | |
352 | }; | |
353 | MODULE_DEVICE_TABLE(spi, ad5449_spi_ids); | |
354 | ||
355 | static struct spi_driver ad5449_spi_driver = { | |
356 | .driver = { | |
357 | .name = "ad5449", | |
8341dc04 LPC |
358 | }, |
359 | .probe = ad5449_spi_probe, | |
fc52692c | 360 | .remove = ad5449_spi_remove, |
8341dc04 LPC |
361 | .id_table = ad5449_spi_ids, |
362 | }; | |
363 | module_spi_driver(ad5449_spi_driver); | |
364 | ||
365 | MODULE_AUTHOR("Lars-Peter Clausen <[email protected]>"); | |
366 | MODULE_DESCRIPTION("Analog Devices AD5449 and similar DACs"); | |
367 | MODULE_LICENSE("GPL v2"); |