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