Commit | Line | Data |
---|---|---|
349282d8 MH |
1 | /* |
2 | * AD7466/7/8 AD7476/5/7/8 (A) SPI ADC 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 | ||
20 | #include "../iio.h" | |
21 | #include "../sysfs.h" | |
22 | #include "../ring_generic.h" | |
23 | #include "adc.h" | |
24 | ||
25 | #include "ad7476.h" | |
26 | ||
27 | static int ad7476_scan_direct(struct ad7476_state *st) | |
28 | { | |
29 | struct spi_device *spi = st->spi; | |
30 | int ret; | |
31 | ||
32 | ret = spi_sync(spi, &st->msg); | |
33 | if (ret) | |
34 | return ret; | |
35 | ||
36 | return (st->data[0] << 8) | st->data[1]; | |
37 | } | |
38 | ||
39 | static ssize_t ad7476_scan(struct device *dev, | |
40 | struct device_attribute *attr, | |
41 | char *buf) | |
42 | { | |
43 | struct iio_dev *dev_info = dev_get_drvdata(dev); | |
44 | struct ad7476_state *st = dev_info->dev_data; | |
45 | int ret; | |
46 | ||
47 | mutex_lock(&dev_info->mlock); | |
48 | if (iio_ring_enabled(dev_info)) | |
49 | ret = ad7476_scan_from_ring(st); | |
50 | else | |
51 | ret = ad7476_scan_direct(st); | |
52 | mutex_unlock(&dev_info->mlock); | |
53 | ||
54 | if (ret < 0) | |
55 | return ret; | |
56 | ||
57 | return sprintf(buf, "%d\n", (ret >> st->chip_info->res_shift) & | |
58 | RES_MASK(st->chip_info->bits)); | |
59 | } | |
60 | static IIO_DEV_ATTR_IN_RAW(0, ad7476_scan, 0); | |
61 | ||
62 | static ssize_t ad7476_show_scale(struct device *dev, | |
63 | struct device_attribute *attr, | |
64 | char *buf) | |
65 | { | |
66 | /* Driver currently only support internal vref */ | |
67 | struct iio_dev *dev_info = dev_get_drvdata(dev); | |
68 | struct ad7476_state *st = iio_dev_get_devdata(dev_info); | |
69 | /* Corresponds to Vref / 2^(bits) */ | |
70 | ||
71 | if ((1 << (st->chip_info->bits + 1)) > st->int_vref_mv) | |
72 | return sprintf(buf, "%d/2^%d\n", | |
73 | st->int_vref_mv, st->chip_info->bits); | |
74 | else | |
75 | return sprintf(buf, "%d\n", | |
76 | st->int_vref_mv >> st->chip_info->bits); | |
77 | } | |
78 | static IIO_DEVICE_ATTR(in_scale, S_IRUGO, ad7476_show_scale, NULL, 0); | |
79 | ||
80 | static ssize_t ad7476_show_name(struct device *dev, | |
81 | struct device_attribute *attr, | |
82 | char *buf) | |
83 | { | |
84 | struct iio_dev *dev_info = dev_get_drvdata(dev); | |
85 | struct ad7476_state *st = iio_dev_get_devdata(dev_info); | |
86 | ||
87 | return sprintf(buf, "%s\n", spi_get_device_id(st->spi)->name); | |
88 | } | |
89 | static IIO_DEVICE_ATTR(name, S_IRUGO, ad7476_show_name, NULL, 0); | |
90 | ||
91 | static struct attribute *ad7476_attributes[] = { | |
92 | &iio_dev_attr_in0_raw.dev_attr.attr, | |
93 | &iio_dev_attr_in_scale.dev_attr.attr, | |
94 | &iio_dev_attr_name.dev_attr.attr, | |
95 | NULL, | |
96 | }; | |
97 | ||
98 | static const struct attribute_group ad7476_attribute_group = { | |
99 | .attrs = ad7476_attributes, | |
100 | }; | |
101 | ||
102 | static const struct ad7476_chip_info ad7476_chip_info_tbl[] = { | |
103 | [ID_AD7466] = { | |
104 | .bits = 12, | |
105 | .storagebits = 16, | |
106 | .res_shift = 0, | |
107 | .sign = IIO_SCAN_EL_TYPE_UNSIGNED, | |
108 | }, | |
109 | [ID_AD7467] = { | |
110 | .bits = 10, | |
111 | .storagebits = 16, | |
112 | .res_shift = 2, | |
113 | .sign = IIO_SCAN_EL_TYPE_UNSIGNED, | |
114 | }, | |
115 | [ID_AD7468] = { | |
116 | .bits = 8, | |
117 | .storagebits = 16, | |
118 | .res_shift = 4, | |
119 | .sign = IIO_SCAN_EL_TYPE_UNSIGNED, | |
120 | }, | |
121 | [ID_AD7475] = { | |
122 | .bits = 12, | |
123 | .storagebits = 16, | |
124 | .res_shift = 0, | |
125 | .sign = IIO_SCAN_EL_TYPE_UNSIGNED, | |
126 | }, | |
127 | [ID_AD7476] = { | |
128 | .bits = 12, | |
129 | .storagebits = 16, | |
130 | .res_shift = 0, | |
131 | .sign = IIO_SCAN_EL_TYPE_UNSIGNED, | |
132 | }, | |
133 | [ID_AD7477] = { | |
134 | .bits = 10, | |
135 | .storagebits = 16, | |
136 | .res_shift = 2, | |
137 | .sign = IIO_SCAN_EL_TYPE_UNSIGNED, | |
138 | }, | |
139 | [ID_AD7478] = { | |
140 | .bits = 8, | |
141 | .storagebits = 16, | |
142 | .res_shift = 4, | |
143 | .sign = IIO_SCAN_EL_TYPE_UNSIGNED, | |
144 | }, | |
145 | [ID_AD7495] = { | |
146 | .bits = 12, | |
147 | .storagebits = 16, | |
148 | .res_shift = 0, | |
149 | .int_vref_mv = 2500, | |
150 | .sign = IIO_SCAN_EL_TYPE_UNSIGNED, | |
151 | }, | |
152 | }; | |
153 | ||
154 | static int __devinit ad7476_probe(struct spi_device *spi) | |
155 | { | |
156 | struct ad7476_platform_data *pdata = spi->dev.platform_data; | |
157 | struct ad7476_state *st; | |
158 | int ret, voltage_uv = 0; | |
159 | ||
160 | st = kzalloc(sizeof(*st), GFP_KERNEL); | |
161 | if (st == NULL) { | |
162 | ret = -ENOMEM; | |
163 | goto error_ret; | |
164 | } | |
165 | ||
166 | st->reg = regulator_get(&spi->dev, "vcc"); | |
167 | if (!IS_ERR(st->reg)) { | |
168 | ret = regulator_enable(st->reg); | |
169 | if (ret) | |
170 | goto error_put_reg; | |
171 | ||
172 | voltage_uv = regulator_get_voltage(st->reg); | |
173 | } | |
174 | ||
175 | st->chip_info = | |
176 | &ad7476_chip_info_tbl[spi_get_device_id(spi)->driver_data]; | |
177 | ||
178 | if (st->chip_info->int_vref_mv) | |
179 | st->int_vref_mv = st->chip_info->int_vref_mv; | |
180 | else if (pdata && pdata->vref_mv) | |
181 | st->int_vref_mv = pdata->vref_mv; | |
182 | else if (voltage_uv) | |
183 | st->int_vref_mv = voltage_uv / 1000; | |
184 | else | |
185 | dev_warn(&spi->dev, "reference voltage unspecified\n"); | |
186 | ||
187 | spi_set_drvdata(spi, st); | |
188 | ||
189 | atomic_set(&st->protect_ring, 0); | |
190 | st->spi = spi; | |
191 | ||
192 | st->indio_dev = iio_allocate_device(); | |
193 | if (st->indio_dev == NULL) { | |
194 | ret = -ENOMEM; | |
195 | goto error_disable_reg; | |
196 | } | |
197 | ||
198 | /* Estabilish that the iio_dev is a child of the i2c device */ | |
199 | st->indio_dev->dev.parent = &spi->dev; | |
200 | st->indio_dev->attrs = &ad7476_attribute_group; | |
201 | st->indio_dev->dev_data = (void *)(st); | |
202 | st->indio_dev->driver_module = THIS_MODULE; | |
203 | st->indio_dev->modes = INDIO_DIRECT_MODE; | |
204 | ||
205 | /* Setup default message */ | |
206 | ||
207 | st->xfer.rx_buf = &st->data; | |
208 | st->xfer.len = st->chip_info->storagebits / 8; | |
209 | ||
210 | spi_message_init(&st->msg); | |
211 | spi_message_add_tail(&st->xfer, &st->msg); | |
212 | ||
213 | ret = ad7476_register_ring_funcs_and_init(st->indio_dev); | |
214 | if (ret) | |
215 | goto error_free_device; | |
216 | ||
217 | ret = iio_device_register(st->indio_dev); | |
218 | if (ret) | |
219 | goto error_free_device; | |
220 | ||
221 | ret = iio_ring_buffer_register(st->indio_dev->ring, 0); | |
222 | if (ret) | |
223 | goto error_cleanup_ring; | |
224 | return 0; | |
225 | ||
226 | error_cleanup_ring: | |
227 | ad7476_ring_cleanup(st->indio_dev); | |
228 | iio_device_unregister(st->indio_dev); | |
229 | error_free_device: | |
230 | iio_free_device(st->indio_dev); | |
231 | error_disable_reg: | |
232 | if (!IS_ERR(st->reg)) | |
233 | regulator_disable(st->reg); | |
234 | error_put_reg: | |
235 | if (!IS_ERR(st->reg)) | |
236 | regulator_put(st->reg); | |
237 | kfree(st); | |
238 | error_ret: | |
239 | return ret; | |
240 | } | |
241 | ||
242 | static int ad7476_remove(struct spi_device *spi) | |
243 | { | |
244 | struct ad7476_state *st = spi_get_drvdata(spi); | |
245 | struct iio_dev *indio_dev = st->indio_dev; | |
246 | iio_ring_buffer_unregister(indio_dev->ring); | |
247 | ad7476_ring_cleanup(indio_dev); | |
248 | iio_device_unregister(indio_dev); | |
249 | if (!IS_ERR(st->reg)) { | |
250 | regulator_disable(st->reg); | |
251 | regulator_put(st->reg); | |
252 | } | |
253 | kfree(st); | |
254 | return 0; | |
255 | } | |
256 | ||
257 | static const struct spi_device_id ad7476_id[] = { | |
258 | {"ad7466", ID_AD7466}, | |
259 | {"ad7467", ID_AD7467}, | |
260 | {"ad7468", ID_AD7468}, | |
261 | {"ad7475", ID_AD7475}, | |
262 | {"ad7476", ID_AD7476}, | |
263 | {"ad7476a", ID_AD7476}, | |
264 | {"ad7477", ID_AD7477}, | |
265 | {"ad7477a", ID_AD7477}, | |
266 | {"ad7478", ID_AD7478}, | |
267 | {"ad7478a", ID_AD7478}, | |
268 | {"ad7495", ID_AD7495}, | |
269 | {} | |
270 | }; | |
271 | ||
272 | static struct spi_driver ad7476_driver = { | |
273 | .driver = { | |
274 | .name = "ad7476", | |
275 | .bus = &spi_bus_type, | |
276 | .owner = THIS_MODULE, | |
277 | }, | |
278 | .probe = ad7476_probe, | |
279 | .remove = __devexit_p(ad7476_remove), | |
280 | .id_table = ad7476_id, | |
281 | }; | |
282 | ||
283 | static int __init ad7476_init(void) | |
284 | { | |
285 | return spi_register_driver(&ad7476_driver); | |
286 | } | |
287 | module_init(ad7476_init); | |
288 | ||
289 | static void __exit ad7476_exit(void) | |
290 | { | |
291 | spi_unregister_driver(&ad7476_driver); | |
292 | } | |
293 | module_exit(ad7476_exit); | |
294 | ||
295 | MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); | |
296 | MODULE_DESCRIPTION("Analog Devices AD7475/6/7/8(A) AD7466/7/8 ADC"); | |
297 | MODULE_LICENSE("GPL v2"); | |
298 | MODULE_ALIAS("spi:ad7476"); |