Commit | Line | Data |
---|---|---|
7c31b984 MH |
1 | /* |
2 | * AD7298 SPI ADC driver | |
3 | * | |
4 | * Copyright 2011 Analog Devices Inc. | |
5 | * | |
6 | * Licensed under the GPL-2. | |
7 | */ | |
8 | ||
7c31b984 MH |
9 | #include <linux/device.h> |
10 | #include <linux/kernel.h> | |
11 | #include <linux/slab.h> | |
12 | #include <linux/sysfs.h> | |
13 | #include <linux/spi/spi.h> | |
14 | #include <linux/regulator/consumer.h> | |
15 | #include <linux/err.h> | |
16 | #include <linux/delay.h> | |
17 | ||
18 | #include "../iio.h" | |
19 | #include "../sysfs.h" | |
20 | #include "../ring_generic.h" | |
21 | #include "adc.h" | |
22 | ||
23 | #include "ad7298.h" | |
24 | ||
01a99e18 MH |
25 | static struct iio_chan_spec ad7298_channels[] = { |
26 | IIO_CHAN(IIO_TEMP, 0, 1, 0, NULL, 0, 0, | |
27 | (1 << IIO_CHAN_INFO_SCALE_SEPARATE), | |
28 | 9, AD7298_CH_TEMP, IIO_ST('s', 32, 32, 0), 0), | |
29 | IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 0, 0, | |
30 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | |
31 | 0, 0, IIO_ST('u', 12, 16, 0), 0), | |
32 | IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 1, 0, | |
33 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | |
34 | 1, 1, IIO_ST('u', 12, 16, 0), 0), | |
35 | IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 2, 0, | |
36 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | |
37 | 2, 2, IIO_ST('u', 12, 16, 0), 0), | |
38 | IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 3, 0, | |
39 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | |
40 | 3, 3, IIO_ST('u', 12, 16, 0), 0), | |
41 | IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 4, 0, | |
42 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | |
43 | 4, 4, IIO_ST('u', 12, 16, 0), 0), | |
44 | IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 5, 0, | |
45 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | |
46 | 5, 5, IIO_ST('u', 12, 16, 0), 0), | |
47 | IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 6, 0, | |
48 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | |
49 | 6, 6, IIO_ST('u', 12, 16, 0), 0), | |
50 | IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 7, 0, | |
51 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | |
52 | 7, 7, IIO_ST('u', 12, 16, 0), 0), | |
53 | IIO_CHAN_SOFT_TIMESTAMP(8), | |
54 | }; | |
55 | ||
7c31b984 MH |
56 | static int ad7298_scan_direct(struct ad7298_state *st, unsigned ch) |
57 | { | |
58 | int ret; | |
59 | st->tx_buf[0] = cpu_to_be16(AD7298_WRITE | st->ext_ref | | |
60 | (AD7298_CH(0) >> ch)); | |
61 | ||
62 | ret = spi_sync(st->spi, &st->scan_single_msg); | |
63 | if (ret) | |
64 | return ret; | |
65 | ||
66 | return be16_to_cpu(st->rx_buf[0]); | |
67 | } | |
68 | ||
01a99e18 | 69 | static int ad7298_scan_temp(struct ad7298_state *st, int *val) |
7c31b984 | 70 | { |
01a99e18 | 71 | int tmp, ret; |
7c31b984 | 72 | |
01a99e18 MH |
73 | tmp = cpu_to_be16(AD7298_WRITE | AD7298_TSENSE | |
74 | AD7298_TAVG | st->ext_ref); | |
7c31b984 | 75 | |
01a99e18 MH |
76 | ret = spi_write(st->spi, (u8 *)&tmp, 2); |
77 | if (ret) | |
7c31b984 MH |
78 | return ret; |
79 | ||
01a99e18 | 80 | tmp = 0; |
7c31b984 | 81 | |
01a99e18 MH |
82 | ret = spi_write(st->spi, (u8 *)&tmp, 2); |
83 | if (ret) | |
84 | return ret; | |
7c31b984 | 85 | |
7c31b984 | 86 | usleep_range(101, 1000); /* sleep > 100us */ |
01a99e18 MH |
87 | |
88 | ret = spi_read(st->spi, (u8 *)&tmp, 2); | |
89 | if (ret) | |
90 | return ret; | |
7c31b984 MH |
91 | |
92 | tmp = be16_to_cpu(tmp) & RES_MASK(AD7298_BITS); | |
93 | ||
94 | /* | |
95 | * One LSB of the ADC corresponds to 0.25 deg C. | |
96 | * The temperature reading is in 12-bit twos complement format | |
97 | */ | |
98 | ||
99 | if (tmp & (1 << (AD7298_BITS - 1))) { | |
100 | tmp = (4096 - tmp) * 250; | |
101 | tmp -= (2 * tmp); | |
102 | ||
103 | } else { | |
104 | tmp *= 250; /* temperature in milli degrees Celsius */ | |
105 | } | |
106 | ||
01a99e18 | 107 | *val = tmp; |
7c31b984 | 108 | |
01a99e18 MH |
109 | return 0; |
110 | } | |
7c31b984 | 111 | |
01a99e18 MH |
112 | static int ad7298_read_raw(struct iio_dev *dev_info, |
113 | struct iio_chan_spec const *chan, | |
114 | int *val, | |
115 | int *val2, | |
116 | long m) | |
7c31b984 | 117 | { |
01a99e18 MH |
118 | int ret; |
119 | struct ad7298_state *st = dev_info->dev_data; | |
120 | unsigned int scale_uv; | |
121 | ||
122 | switch (m) { | |
123 | case 0: | |
124 | mutex_lock(&dev_info->mlock); | |
125 | if (iio_ring_enabled(dev_info)) { | |
126 | if (chan->address == AD7298_CH_TEMP) | |
127 | ret = -ENODEV; | |
128 | else | |
129 | ret = ad7298_scan_from_ring(st, chan->address); | |
130 | } else { | |
131 | if (chan->address == AD7298_CH_TEMP) | |
132 | ret = ad7298_scan_temp(st, val); | |
133 | else | |
134 | ret = ad7298_scan_direct(st, chan->address); | |
135 | } | |
136 | mutex_unlock(&dev_info->mlock); | |
137 | ||
138 | if (ret < 0) | |
139 | return ret; | |
140 | ||
141 | if (chan->address != AD7298_CH_TEMP) | |
142 | *val = ret & RES_MASK(AD7298_BITS); | |
143 | ||
144 | return IIO_VAL_INT; | |
145 | case (1 << IIO_CHAN_INFO_SCALE_SHARED): | |
146 | scale_uv = (st->int_vref_mv * 1000) >> AD7298_BITS; | |
147 | *val = scale_uv / 1000; | |
148 | *val2 = (scale_uv % 1000) * 1000; | |
149 | return IIO_VAL_INT_PLUS_MICRO; | |
150 | case (1 << IIO_CHAN_INFO_SCALE_SEPARATE): | |
151 | *val = 1; | |
152 | *val2 = 0; | |
153 | return IIO_VAL_INT_PLUS_MICRO; | |
154 | } | |
155 | return -EINVAL; | |
7c31b984 | 156 | } |
7c31b984 MH |
157 | |
158 | static int __devinit ad7298_probe(struct spi_device *spi) | |
159 | { | |
160 | struct ad7298_platform_data *pdata = spi->dev.platform_data; | |
161 | struct ad7298_state *st; | |
162 | int ret; | |
163 | ||
164 | st = kzalloc(sizeof(*st), GFP_KERNEL); | |
165 | if (st == NULL) { | |
166 | ret = -ENOMEM; | |
167 | goto error_ret; | |
168 | } | |
169 | ||
170 | st->reg = regulator_get(&spi->dev, "vcc"); | |
171 | if (!IS_ERR(st->reg)) { | |
172 | ret = regulator_enable(st->reg); | |
173 | if (ret) | |
174 | goto error_put_reg; | |
175 | } | |
176 | ||
177 | spi_set_drvdata(spi, st); | |
178 | ||
7c31b984 MH |
179 | st->spi = spi; |
180 | ||
6f7c8ee5 | 181 | st->indio_dev = iio_allocate_device(0); |
7c31b984 MH |
182 | if (st->indio_dev == NULL) { |
183 | ret = -ENOMEM; | |
184 | goto error_disable_reg; | |
185 | } | |
186 | ||
845bd12a | 187 | st->indio_dev->name = spi_get_device_id(spi)->name; |
7c31b984 | 188 | st->indio_dev->dev.parent = &spi->dev; |
7c31b984 MH |
189 | st->indio_dev->dev_data = (void *)(st); |
190 | st->indio_dev->driver_module = THIS_MODULE; | |
191 | st->indio_dev->modes = INDIO_DIRECT_MODE; | |
01a99e18 MH |
192 | st->indio_dev->channels = ad7298_channels; |
193 | st->indio_dev->num_channels = ARRAY_SIZE(ad7298_channels); | |
194 | st->indio_dev->read_raw = &ad7298_read_raw; | |
7c31b984 MH |
195 | |
196 | /* Setup default message */ | |
197 | ||
198 | st->scan_single_xfer[0].tx_buf = &st->tx_buf[0]; | |
199 | st->scan_single_xfer[0].len = 2; | |
200 | st->scan_single_xfer[0].cs_change = 1; | |
201 | st->scan_single_xfer[1].tx_buf = &st->tx_buf[1]; | |
202 | st->scan_single_xfer[1].len = 2; | |
203 | st->scan_single_xfer[1].cs_change = 1; | |
204 | st->scan_single_xfer[2].rx_buf = &st->rx_buf[0]; | |
205 | st->scan_single_xfer[2].len = 2; | |
206 | ||
207 | spi_message_init(&st->scan_single_msg); | |
208 | spi_message_add_tail(&st->scan_single_xfer[0], &st->scan_single_msg); | |
209 | spi_message_add_tail(&st->scan_single_xfer[1], &st->scan_single_msg); | |
210 | spi_message_add_tail(&st->scan_single_xfer[2], &st->scan_single_msg); | |
211 | ||
212 | if (pdata && pdata->vref_mv) { | |
213 | st->int_vref_mv = pdata->vref_mv; | |
214 | st->ext_ref = AD7298_EXTREF; | |
215 | } else { | |
216 | st->int_vref_mv = AD7298_INTREF_mV; | |
217 | } | |
218 | ||
219 | ret = ad7298_register_ring_funcs_and_init(st->indio_dev); | |
220 | if (ret) | |
221 | goto error_free_device; | |
222 | ||
223 | ret = iio_device_register(st->indio_dev); | |
224 | if (ret) | |
225 | goto error_free_device; | |
226 | ||
01a99e18 MH |
227 | ret = iio_ring_buffer_register_ex(st->indio_dev->ring, 0, |
228 | &ad7298_channels[1], /* skip temp0 */ | |
229 | ARRAY_SIZE(ad7298_channels) - 1); | |
7c31b984 MH |
230 | if (ret) |
231 | goto error_cleanup_ring; | |
232 | return 0; | |
233 | ||
234 | error_cleanup_ring: | |
235 | ad7298_ring_cleanup(st->indio_dev); | |
236 | iio_device_unregister(st->indio_dev); | |
237 | error_free_device: | |
238 | iio_free_device(st->indio_dev); | |
239 | error_disable_reg: | |
240 | if (!IS_ERR(st->reg)) | |
241 | regulator_disable(st->reg); | |
242 | error_put_reg: | |
243 | if (!IS_ERR(st->reg)) | |
244 | regulator_put(st->reg); | |
245 | kfree(st); | |
246 | error_ret: | |
247 | return ret; | |
248 | } | |
249 | ||
250 | static int __devexit ad7298_remove(struct spi_device *spi) | |
251 | { | |
252 | struct ad7298_state *st = spi_get_drvdata(spi); | |
253 | struct iio_dev *indio_dev = st->indio_dev; | |
254 | ||
255 | iio_ring_buffer_unregister(indio_dev->ring); | |
256 | ad7298_ring_cleanup(indio_dev); | |
257 | iio_device_unregister(indio_dev); | |
258 | if (!IS_ERR(st->reg)) { | |
259 | regulator_disable(st->reg); | |
260 | regulator_put(st->reg); | |
261 | } | |
262 | kfree(st); | |
263 | return 0; | |
264 | } | |
265 | ||
266 | static const struct spi_device_id ad7298_id[] = { | |
267 | {"ad7298", 0}, | |
268 | {} | |
269 | }; | |
270 | ||
271 | static struct spi_driver ad7298_driver = { | |
272 | .driver = { | |
273 | .name = "ad7298", | |
274 | .bus = &spi_bus_type, | |
275 | .owner = THIS_MODULE, | |
276 | }, | |
277 | .probe = ad7298_probe, | |
278 | .remove = __devexit_p(ad7298_remove), | |
279 | .id_table = ad7298_id, | |
280 | }; | |
281 | ||
282 | static int __init ad7298_init(void) | |
283 | { | |
284 | return spi_register_driver(&ad7298_driver); | |
285 | } | |
286 | module_init(ad7298_init); | |
287 | ||
288 | static void __exit ad7298_exit(void) | |
289 | { | |
290 | spi_unregister_driver(&ad7298_driver); | |
291 | } | |
292 | module_exit(ad7298_exit); | |
293 | ||
294 | MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); | |
295 | MODULE_DESCRIPTION("Analog Devices AD7298 ADC"); | |
296 | MODULE_LICENSE("GPL v2"); | |
297 | MODULE_ALIAS("spi:ad7298"); |