diff options
-rw-r--r-- | drivers/iio/Kconfig | 1 | ||||
-rw-r--r-- | drivers/iio/Makefile | 1 | ||||
-rw-r--r-- | drivers/iio/adc/Kconfig | 16 | ||||
-rw-r--r-- | drivers/iio/adc/Makefile | 5 | ||||
-rw-r--r-- | drivers/iio/adc/at91_adc.c | 672 |
5 files changed, 695 insertions, 0 deletions
diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig index bb1e35c811da..56eecefcec75 100644 --- a/drivers/iio/Kconfig +++ b/drivers/iio/Kconfig | |||
@@ -48,6 +48,7 @@ config IIO_CONSUMERS_PER_TRIGGER | |||
48 | This value controls the maximum number of consumers that a | 48 | This value controls the maximum number of consumers that a |
49 | given trigger may handle. Default is 2. | 49 | given trigger may handle. Default is 2. |
50 | 50 | ||
51 | source "drivers/iio/adc/Kconfig" | ||
51 | source "drivers/iio/amplifiers/Kconfig" | 52 | source "drivers/iio/amplifiers/Kconfig" |
52 | 53 | ||
53 | endif # IIO | 54 | endif # IIO |
diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile index 55524916aa56..e425afd1480c 100644 --- a/drivers/iio/Makefile +++ b/drivers/iio/Makefile | |||
@@ -9,4 +9,5 @@ industrialio-$(CONFIG_IIO_TRIGGER) += industrialio-trigger.o | |||
9 | 9 | ||
10 | obj-$(CONFIG_IIO_KFIFO_BUF) += kfifo_buf.o | 10 | obj-$(CONFIG_IIO_KFIFO_BUF) += kfifo_buf.o |
11 | 11 | ||
12 | obj-y += adc/ | ||
12 | obj-y += amplifiers/ | 13 | obj-y += amplifiers/ |
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig new file mode 100644 index 000000000000..9a0df8123cc4 --- /dev/null +++ b/drivers/iio/adc/Kconfig | |||
@@ -0,0 +1,16 @@ | |||
1 | # | ||
2 | # ADC drivers | ||
3 | # | ||
4 | menu "Analog to digital converters" | ||
5 | |||
6 | config AT91_ADC | ||
7 | tristate "Atmel AT91 ADC" | ||
8 | depends on ARCH_AT91 | ||
9 | select IIO_BUFFER | ||
10 | select IIO_KFIFO_BUF | ||
11 | select IIO_TRIGGER | ||
12 | select SYSFS | ||
13 | help | ||
14 | Say yes here to build support for Atmel AT91 ADC. | ||
15 | |||
16 | endmenu | ||
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile new file mode 100644 index 000000000000..175c8d41ea99 --- /dev/null +++ b/drivers/iio/adc/Makefile | |||
@@ -0,0 +1,5 @@ | |||
1 | # | ||
2 | # Makefile for IIO ADC drivers | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_AT91_ADC) += at91_adc.o | ||
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c new file mode 100644 index 000000000000..e2eb6139daf7 --- /dev/null +++ b/drivers/iio/adc/at91_adc.c | |||
@@ -0,0 +1,672 @@ | |||
1 | /* | ||
2 | * Driver for the ADC present in the Atmel AT91 evaluation boards. | ||
3 | * | ||
4 | * Copyright 2011 Free Electrons | ||
5 | * | ||
6 | * Licensed under the GPLv2 or later. | ||
7 | */ | ||
8 | |||
9 | #include <linux/bitmap.h> | ||
10 | #include <linux/bitops.h> | ||
11 | #include <linux/clk.h> | ||
12 | #include <linux/err.h> | ||
13 | #include <linux/io.h> | ||
14 | #include <linux/interrupt.h> | ||
15 | #include <linux/jiffies.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/platform_device.h> | ||
19 | #include <linux/sched.h> | ||
20 | #include <linux/slab.h> | ||
21 | #include <linux/wait.h> | ||
22 | |||
23 | #include <linux/platform_data/at91_adc.h> | ||
24 | |||
25 | #include <linux/iio/iio.h> | ||
26 | #include <linux/iio/buffer.h> | ||
27 | #include <linux/iio/kfifo_buf.h> | ||
28 | #include <linux/iio/trigger.h> | ||
29 | #include <linux/iio/trigger_consumer.h> | ||
30 | |||
31 | #include <mach/at91_adc.h> | ||
32 | |||
33 | #define AT91_ADC_CHAN(st, ch) \ | ||
34 | (st->registers->channel_base + (ch * 4)) | ||
35 | #define at91_adc_readl(st, reg) \ | ||
36 | (readl_relaxed(st->reg_base + reg)) | ||
37 | #define at91_adc_writel(st, reg, val) \ | ||
38 | (writel_relaxed(val, st->reg_base + reg)) | ||
39 | |||
40 | struct at91_adc_state { | ||
41 | struct clk *adc_clk; | ||
42 | u16 *buffer; | ||
43 | unsigned long channels_mask; | ||
44 | struct clk *clk; | ||
45 | bool done; | ||
46 | int irq; | ||
47 | bool irq_enabled; | ||
48 | u16 last_value; | ||
49 | struct mutex lock; | ||
50 | u8 num_channels; | ||
51 | void __iomem *reg_base; | ||
52 | struct at91_adc_reg_desc *registers; | ||
53 | u8 startup_time; | ||
54 | struct iio_trigger **trig; | ||
55 | struct at91_adc_trigger *trigger_list; | ||
56 | u32 trigger_number; | ||
57 | bool use_external; | ||
58 | u32 vref_mv; | ||
59 | wait_queue_head_t wq_data_avail; | ||
60 | }; | ||
61 | |||
62 | static irqreturn_t at91_adc_trigger_handler(int irq, void *p) | ||
63 | { | ||
64 | struct iio_poll_func *pf = p; | ||
65 | struct iio_dev *idev = pf->indio_dev; | ||
66 | struct at91_adc_state *st = iio_priv(idev); | ||
67 | struct iio_buffer *buffer = idev->buffer; | ||
68 | int i, j = 0; | ||
69 | |||
70 | for (i = 0; i < idev->masklength; i++) { | ||
71 | if (!test_bit(i, idev->active_scan_mask)) | ||
72 | continue; | ||
73 | st->buffer[j] = at91_adc_readl(st, AT91_ADC_CHAN(st, i)); | ||
74 | j++; | ||
75 | } | ||
76 | |||
77 | if (idev->scan_timestamp) { | ||
78 | s64 *timestamp = (s64 *)((u8 *)st->buffer + | ||
79 | ALIGN(j, sizeof(s64))); | ||
80 | *timestamp = pf->timestamp; | ||
81 | } | ||
82 | |||
83 | buffer->access->store_to(buffer, (u8 *)st->buffer, pf->timestamp); | ||
84 | |||
85 | iio_trigger_notify_done(idev->trig); | ||
86 | st->irq_enabled = true; | ||
87 | |||
88 | /* Needed to ACK the DRDY interruption */ | ||
89 | at91_adc_readl(st, AT91_ADC_LCDR); | ||
90 | |||
91 | enable_irq(st->irq); | ||
92 | |||
93 | return IRQ_HANDLED; | ||
94 | } | ||
95 | |||
96 | static irqreturn_t at91_adc_eoc_trigger(int irq, void *private) | ||
97 | { | ||
98 | struct iio_dev *idev = private; | ||
99 | struct at91_adc_state *st = iio_priv(idev); | ||
100 | u32 status = at91_adc_readl(st, st->registers->status_register); | ||
101 | |||
102 | if (!(status & st->registers->drdy_mask)) | ||
103 | return IRQ_HANDLED; | ||
104 | |||
105 | if (iio_buffer_enabled(idev)) { | ||
106 | disable_irq_nosync(irq); | ||
107 | st->irq_enabled = false; | ||
108 | iio_trigger_poll(idev->trig, iio_get_time_ns()); | ||
109 | } else { | ||
110 | st->last_value = at91_adc_readl(st, AT91_ADC_LCDR); | ||
111 | st->done = true; | ||
112 | wake_up_interruptible(&st->wq_data_avail); | ||
113 | } | ||
114 | |||
115 | return IRQ_HANDLED; | ||
116 | } | ||
117 | |||
118 | static int at91_adc_channel_init(struct iio_dev *idev) | ||
119 | { | ||
120 | struct at91_adc_state *st = iio_priv(idev); | ||
121 | struct iio_chan_spec *chan_array, *timestamp; | ||
122 | int bit, idx = 0; | ||
123 | |||
124 | idev->num_channels = bitmap_weight(&st->channels_mask, | ||
125 | st->num_channels) + 1; | ||
126 | |||
127 | chan_array = devm_kzalloc(&idev->dev, | ||
128 | ((idev->num_channels + 1) * | ||
129 | sizeof(struct iio_chan_spec)), | ||
130 | GFP_KERNEL); | ||
131 | |||
132 | if (!chan_array) | ||
133 | return -ENOMEM; | ||
134 | |||
135 | for_each_set_bit(bit, &st->channels_mask, st->num_channels) { | ||
136 | struct iio_chan_spec *chan = chan_array + idx; | ||
137 | |||
138 | chan->type = IIO_VOLTAGE; | ||
139 | chan->indexed = 1; | ||
140 | chan->channel = bit; | ||
141 | chan->scan_index = idx; | ||
142 | chan->scan_type.sign = 'u'; | ||
143 | chan->scan_type.realbits = 10; | ||
144 | chan->scan_type.storagebits = 16; | ||
145 | chan->info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT | | ||
146 | IIO_CHAN_INFO_RAW_SEPARATE_BIT; | ||
147 | idx++; | ||
148 | } | ||
149 | timestamp = chan_array + idx; | ||
150 | |||
151 | timestamp->type = IIO_TIMESTAMP; | ||
152 | timestamp->channel = -1; | ||
153 | timestamp->scan_index = idx; | ||
154 | timestamp->scan_type.sign = 's'; | ||
155 | timestamp->scan_type.realbits = 64; | ||
156 | timestamp->scan_type.storagebits = 64; | ||
157 | |||
158 | idev->channels = chan_array; | ||
159 | return idev->num_channels; | ||
160 | } | ||
161 | |||
162 | static u8 at91_adc_get_trigger_value_by_name(struct iio_dev *idev, | ||
163 | struct at91_adc_trigger *triggers, | ||
164 | const char *trigger_name) | ||
165 | { | ||
166 | struct at91_adc_state *st = iio_priv(idev); | ||
167 | u8 value = 0; | ||
168 | int i; | ||
169 | |||
170 | for (i = 0; i < st->trigger_number; i++) { | ||
171 | char *name = kasprintf(GFP_KERNEL, | ||
172 | "%s-dev%d-%s", | ||
173 | idev->name, | ||
174 | idev->id, | ||
175 | triggers[i].name); | ||
176 | if (!name) | ||
177 | return -ENOMEM; | ||
178 | |||
179 | if (strcmp(trigger_name, name) == 0) { | ||
180 | value = triggers[i].value; | ||
181 | kfree(name); | ||
182 | break; | ||
183 | } | ||
184 | |||
185 | kfree(name); | ||
186 | } | ||
187 | |||
188 | return value; | ||
189 | } | ||
190 | |||
191 | static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state) | ||
192 | { | ||
193 | struct iio_dev *idev = trig->private_data; | ||
194 | struct at91_adc_state *st = iio_priv(idev); | ||
195 | struct iio_buffer *buffer = idev->buffer; | ||
196 | struct at91_adc_reg_desc *reg = st->registers; | ||
197 | u32 status = at91_adc_readl(st, reg->trigger_register); | ||
198 | u8 value; | ||
199 | u8 bit; | ||
200 | |||
201 | value = at91_adc_get_trigger_value_by_name(idev, | ||
202 | st->trigger_list, | ||
203 | idev->trig->name); | ||
204 | if (value == 0) | ||
205 | return -EINVAL; | ||
206 | |||
207 | if (state) { | ||
208 | st->buffer = kmalloc(idev->scan_bytes, GFP_KERNEL); | ||
209 | if (st->buffer == NULL) | ||
210 | return -ENOMEM; | ||
211 | |||
212 | at91_adc_writel(st, reg->trigger_register, | ||
213 | status | value); | ||
214 | |||
215 | for_each_set_bit(bit, buffer->scan_mask, | ||
216 | st->num_channels) { | ||
217 | struct iio_chan_spec const *chan = idev->channels + bit; | ||
218 | at91_adc_writel(st, AT91_ADC_CHER, | ||
219 | AT91_ADC_CH(chan->channel)); | ||
220 | } | ||
221 | |||
222 | at91_adc_writel(st, AT91_ADC_IER, reg->drdy_mask); | ||
223 | |||
224 | } else { | ||
225 | at91_adc_writel(st, AT91_ADC_IDR, reg->drdy_mask); | ||
226 | |||
227 | at91_adc_writel(st, reg->trigger_register, | ||
228 | status & ~value); | ||
229 | |||
230 | for_each_set_bit(bit, buffer->scan_mask, | ||
231 | st->num_channels) { | ||
232 | struct iio_chan_spec const *chan = idev->channels + bit; | ||
233 | at91_adc_writel(st, AT91_ADC_CHDR, | ||
234 | AT91_ADC_CH(chan->channel)); | ||
235 | } | ||
236 | kfree(st->buffer); | ||
237 | } | ||
238 | |||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | static const struct iio_trigger_ops at91_adc_trigger_ops = { | ||
243 | .owner = THIS_MODULE, | ||
244 | .set_trigger_state = &at91_adc_configure_trigger, | ||
245 | }; | ||
246 | |||
247 | static struct iio_trigger *at91_adc_allocate_trigger(struct iio_dev *idev, | ||
248 | struct at91_adc_trigger *trigger) | ||
249 | { | ||
250 | struct iio_trigger *trig; | ||
251 | int ret; | ||
252 | |||
253 | trig = iio_trigger_alloc("%s-dev%d-%s", idev->name, | ||
254 | idev->id, trigger->name); | ||
255 | if (trig == NULL) | ||
256 | return NULL; | ||
257 | |||
258 | trig->dev.parent = idev->dev.parent; | ||
259 | trig->private_data = idev; | ||
260 | trig->ops = &at91_adc_trigger_ops; | ||
261 | |||
262 | ret = iio_trigger_register(trig); | ||
263 | if (ret) | ||
264 | return NULL; | ||
265 | |||
266 | return trig; | ||
267 | } | ||
268 | |||
269 | static int at91_adc_trigger_init(struct iio_dev *idev) | ||
270 | { | ||
271 | struct at91_adc_state *st = iio_priv(idev); | ||
272 | int i, ret; | ||
273 | |||
274 | st->trig = devm_kzalloc(&idev->dev, | ||
275 | st->trigger_number * sizeof(st->trig), | ||
276 | GFP_KERNEL); | ||
277 | |||
278 | if (st->trig == NULL) { | ||
279 | ret = -ENOMEM; | ||
280 | goto error_ret; | ||
281 | } | ||
282 | |||
283 | for (i = 0; i < st->trigger_number; i++) { | ||
284 | if (st->trigger_list[i].is_external && !(st->use_external)) | ||
285 | continue; | ||
286 | |||
287 | st->trig[i] = at91_adc_allocate_trigger(idev, | ||
288 | st->trigger_list + i); | ||
289 | if (st->trig[i] == NULL) { | ||
290 | dev_err(&idev->dev, | ||
291 | "Could not allocate trigger %d\n", i); | ||
292 | ret = -ENOMEM; | ||
293 | goto error_trigger; | ||
294 | } | ||
295 | } | ||
296 | |||
297 | return 0; | ||
298 | |||
299 | error_trigger: | ||
300 | for (i--; i >= 0; i--) { | ||
301 | iio_trigger_unregister(st->trig[i]); | ||
302 | iio_trigger_free(st->trig[i]); | ||
303 | } | ||
304 | error_ret: | ||
305 | return ret; | ||
306 | } | ||
307 | |||
308 | static void at91_adc_trigger_remove(struct iio_dev *idev) | ||
309 | { | ||
310 | struct at91_adc_state *st = iio_priv(idev); | ||
311 | int i; | ||
312 | |||
313 | for (i = 0; i < st->trigger_number; i++) { | ||
314 | iio_trigger_unregister(st->trig[i]); | ||
315 | iio_trigger_free(st->trig[i]); | ||
316 | } | ||
317 | } | ||
318 | |||
319 | static const struct iio_buffer_setup_ops at91_adc_buffer_ops = { | ||
320 | .preenable = &iio_sw_buffer_preenable, | ||
321 | .postenable = &iio_triggered_buffer_postenable, | ||
322 | .predisable = &iio_triggered_buffer_predisable, | ||
323 | }; | ||
324 | |||
325 | static int at91_adc_buffer_init(struct iio_dev *idev) | ||
326 | { | ||
327 | int ret; | ||
328 | |||
329 | idev->buffer = iio_kfifo_allocate(idev); | ||
330 | if (!idev->buffer) { | ||
331 | ret = -ENOMEM; | ||
332 | goto error_ret; | ||
333 | } | ||
334 | |||
335 | idev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time, | ||
336 | &at91_adc_trigger_handler, | ||
337 | IRQF_ONESHOT, | ||
338 | idev, | ||
339 | "%s-consumer%d", | ||
340 | idev->name, | ||
341 | idev->id); | ||
342 | if (idev->pollfunc == NULL) { | ||
343 | ret = -ENOMEM; | ||
344 | goto error_pollfunc; | ||
345 | } | ||
346 | |||
347 | idev->setup_ops = &at91_adc_buffer_ops; | ||
348 | idev->modes |= INDIO_BUFFER_TRIGGERED; | ||
349 | |||
350 | ret = iio_buffer_register(idev, | ||
351 | idev->channels, | ||
352 | idev->num_channels); | ||
353 | if (ret) | ||
354 | goto error_register; | ||
355 | |||
356 | return 0; | ||
357 | |||
358 | error_register: | ||
359 | iio_dealloc_pollfunc(idev->pollfunc); | ||
360 | error_pollfunc: | ||
361 | iio_kfifo_free(idev->buffer); | ||
362 | error_ret: | ||
363 | return ret; | ||
364 | } | ||
365 | |||
366 | static void at91_adc_buffer_remove(struct iio_dev *idev) | ||
367 | { | ||
368 | iio_buffer_unregister(idev); | ||
369 | iio_dealloc_pollfunc(idev->pollfunc); | ||
370 | iio_kfifo_free(idev->buffer); | ||
371 | } | ||
372 | |||
373 | static int at91_adc_read_raw(struct iio_dev *idev, | ||
374 | struct iio_chan_spec const *chan, | ||
375 | int *val, int *val2, long mask) | ||
376 | { | ||
377 | struct at91_adc_state *st = iio_priv(idev); | ||
378 | int ret; | ||
379 | |||
380 | switch (mask) { | ||
381 | case IIO_CHAN_INFO_RAW: | ||
382 | mutex_lock(&st->lock); | ||
383 | |||
384 | at91_adc_writel(st, AT91_ADC_CHER, | ||
385 | AT91_ADC_CH(chan->channel)); | ||
386 | at91_adc_writel(st, AT91_ADC_IER, st->registers->drdy_mask); | ||
387 | at91_adc_writel(st, AT91_ADC_CR, AT91_ADC_START); | ||
388 | |||
389 | ret = wait_event_interruptible_timeout(st->wq_data_avail, | ||
390 | st->done, | ||
391 | msecs_to_jiffies(1000)); | ||
392 | if (ret == 0) | ||
393 | return -ETIMEDOUT; | ||
394 | else if (ret < 0) | ||
395 | return ret; | ||
396 | |||
397 | *val = st->last_value; | ||
398 | |||
399 | at91_adc_writel(st, AT91_ADC_CHDR, | ||
400 | AT91_ADC_CH(chan->channel)); | ||
401 | at91_adc_writel(st, AT91_ADC_IDR, st->registers->drdy_mask); | ||
402 | |||
403 | st->last_value = 0; | ||
404 | st->done = false; | ||
405 | mutex_unlock(&st->lock); | ||
406 | return IIO_VAL_INT; | ||
407 | |||
408 | case IIO_CHAN_INFO_SCALE: | ||
409 | *val = (st->vref_mv * 1000) >> chan->scan_type.realbits; | ||
410 | *val2 = 0; | ||
411 | return IIO_VAL_INT_PLUS_MICRO; | ||
412 | default: | ||
413 | break; | ||
414 | } | ||
415 | return -EINVAL; | ||
416 | } | ||
417 | |||
418 | static int at91_adc_probe_pdata(struct at91_adc_state *st, | ||
419 | struct platform_device *pdev) | ||
420 | { | ||
421 | struct at91_adc_data *pdata = pdev->dev.platform_data; | ||
422 | |||
423 | if (!pdata) | ||
424 | return -EINVAL; | ||
425 | |||
426 | st->use_external = pdata->use_external_triggers; | ||
427 | st->vref_mv = pdata->vref; | ||
428 | st->channels_mask = pdata->channels_used; | ||
429 | st->num_channels = pdata->num_channels; | ||
430 | st->startup_time = pdata->startup_time; | ||
431 | st->trigger_number = pdata->trigger_number; | ||
432 | st->trigger_list = pdata->trigger_list; | ||
433 | st->registers = pdata->registers; | ||
434 | |||
435 | return 0; | ||
436 | } | ||
437 | |||
438 | static const struct iio_info at91_adc_info = { | ||
439 | .driver_module = THIS_MODULE, | ||
440 | .read_raw = &at91_adc_read_raw, | ||
441 | }; | ||
442 | |||
443 | static int __devinit at91_adc_probe(struct platform_device *pdev) | ||
444 | { | ||
445 | unsigned int prsc, mstrclk, ticks, adc_clk; | ||
446 | int ret; | ||
447 | struct iio_dev *idev; | ||
448 | struct at91_adc_state *st; | ||
449 | struct resource *res; | ||
450 | |||
451 | idev = iio_device_alloc(sizeof(struct at91_adc_state)); | ||
452 | if (idev == NULL) { | ||
453 | ret = -ENOMEM; | ||
454 | goto error_ret; | ||
455 | } | ||
456 | |||
457 | st = iio_priv(idev); | ||
458 | |||
459 | ret = at91_adc_probe_pdata(st, pdev); | ||
460 | if (ret) { | ||
461 | dev_err(&pdev->dev, "No platform data available.\n"); | ||
462 | ret = -EINVAL; | ||
463 | goto error_free_device; | ||
464 | } | ||
465 | |||
466 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
467 | if (!res) { | ||
468 | dev_err(&pdev->dev, "No resource defined\n"); | ||
469 | ret = -ENXIO; | ||
470 | goto error_ret; | ||
471 | } | ||
472 | |||
473 | platform_set_drvdata(pdev, idev); | ||
474 | |||
475 | idev->dev.parent = &pdev->dev; | ||
476 | idev->name = dev_name(&pdev->dev); | ||
477 | idev->modes = INDIO_DIRECT_MODE; | ||
478 | idev->info = &at91_adc_info; | ||
479 | |||
480 | st->irq = platform_get_irq(pdev, 0); | ||
481 | if (st->irq < 0) { | ||
482 | dev_err(&pdev->dev, "No IRQ ID is designated\n"); | ||
483 | ret = -ENODEV; | ||
484 | goto error_free_device; | ||
485 | } | ||
486 | |||
487 | if (!request_mem_region(res->start, resource_size(res), | ||
488 | "AT91 adc registers")) { | ||
489 | dev_err(&pdev->dev, "Resources are unavailable.\n"); | ||
490 | ret = -EBUSY; | ||
491 | goto error_free_device; | ||
492 | } | ||
493 | |||
494 | st->reg_base = ioremap(res->start, resource_size(res)); | ||
495 | if (!st->reg_base) { | ||
496 | dev_err(&pdev->dev, "Failed to map registers.\n"); | ||
497 | ret = -ENOMEM; | ||
498 | goto error_release_mem; | ||
499 | } | ||
500 | |||
501 | /* | ||
502 | * Disable all IRQs before setting up the handler | ||
503 | */ | ||
504 | at91_adc_writel(st, AT91_ADC_CR, AT91_ADC_SWRST); | ||
505 | at91_adc_writel(st, AT91_ADC_IDR, 0xFFFFFFFF); | ||
506 | ret = request_irq(st->irq, | ||
507 | at91_adc_eoc_trigger, | ||
508 | 0, | ||
509 | pdev->dev.driver->name, | ||
510 | idev); | ||
511 | if (ret) { | ||
512 | dev_err(&pdev->dev, "Failed to allocate IRQ.\n"); | ||
513 | goto error_unmap_reg; | ||
514 | } | ||
515 | |||
516 | st->clk = clk_get(&pdev->dev, "adc_clk"); | ||
517 | if (IS_ERR(st->clk)) { | ||
518 | dev_err(&pdev->dev, "Failed to get the clock.\n"); | ||
519 | ret = PTR_ERR(st->clk); | ||
520 | goto error_free_irq; | ||
521 | } | ||
522 | |||
523 | ret = clk_prepare(st->clk); | ||
524 | if (ret) { | ||
525 | dev_err(&pdev->dev, "Could not prepare the clock.\n"); | ||
526 | goto error_free_clk; | ||
527 | } | ||
528 | |||
529 | ret = clk_enable(st->clk); | ||
530 | if (ret) { | ||
531 | dev_err(&pdev->dev, "Could not enable the clock.\n"); | ||
532 | goto error_unprepare_clk; | ||
533 | } | ||
534 | |||
535 | st->adc_clk = clk_get(&pdev->dev, "adc_op_clk"); | ||
536 | if (IS_ERR(st->adc_clk)) { | ||
537 | dev_err(&pdev->dev, "Failed to get the ADC clock.\n"); | ||
538 | ret = PTR_ERR(st->clk); | ||
539 | goto error_disable_clk; | ||
540 | } | ||
541 | |||
542 | ret = clk_prepare(st->adc_clk); | ||
543 | if (ret) { | ||
544 | dev_err(&pdev->dev, "Could not prepare the ADC clock.\n"); | ||
545 | goto error_free_adc_clk; | ||
546 | } | ||
547 | |||
548 | ret = clk_enable(st->adc_clk); | ||
549 | if (ret) { | ||
550 | dev_err(&pdev->dev, "Could not enable the ADC clock.\n"); | ||
551 | goto error_unprepare_adc_clk; | ||
552 | } | ||
553 | |||
554 | /* | ||
555 | * Prescaler rate computation using the formula from the Atmel's | ||
556 | * datasheet : ADC Clock = MCK / ((Prescaler + 1) * 2), ADC Clock being | ||
557 | * specified by the electrical characteristics of the board. | ||
558 | */ | ||
559 | mstrclk = clk_get_rate(st->clk); | ||
560 | adc_clk = clk_get_rate(st->adc_clk); | ||
561 | prsc = (mstrclk / (2 * adc_clk)) - 1; | ||
562 | |||
563 | if (!st->startup_time) { | ||
564 | dev_err(&pdev->dev, "No startup time available.\n"); | ||
565 | ret = -EINVAL; | ||
566 | goto error_disable_adc_clk; | ||
567 | } | ||
568 | |||
569 | /* | ||
570 | * Number of ticks needed to cover the startup time of the ADC as | ||
571 | * defined in the electrical characteristics of the board, divided by 8. | ||
572 | * The formula thus is : Startup Time = (ticks + 1) * 8 / ADC Clock | ||
573 | */ | ||
574 | ticks = round_up((st->startup_time * adc_clk / | ||
575 | 1000000) - 1, 8) / 8; | ||
576 | at91_adc_writel(st, AT91_ADC_MR, | ||
577 | (AT91_ADC_PRESCAL_(prsc) & AT91_ADC_PRESCAL) | | ||
578 | (AT91_ADC_STARTUP_(ticks) & AT91_ADC_STARTUP)); | ||
579 | |||
580 | /* Setup the ADC channels available on the board */ | ||
581 | ret = at91_adc_channel_init(idev); | ||
582 | if (ret < 0) { | ||
583 | dev_err(&pdev->dev, "Couldn't initialize the channels.\n"); | ||
584 | goto error_disable_adc_clk; | ||
585 | } | ||
586 | |||
587 | init_waitqueue_head(&st->wq_data_avail); | ||
588 | mutex_init(&st->lock); | ||
589 | |||
590 | ret = at91_adc_buffer_init(idev); | ||
591 | if (ret < 0) { | ||
592 | dev_err(&pdev->dev, "Couldn't initialize the buffer.\n"); | ||
593 | goto error_disable_adc_clk; | ||
594 | } | ||
595 | |||
596 | ret = at91_adc_trigger_init(idev); | ||
597 | if (ret < 0) { | ||
598 | dev_err(&pdev->dev, "Couldn't setup the triggers.\n"); | ||
599 | goto error_unregister_buffer; | ||
600 | } | ||
601 | |||
602 | ret = iio_device_register(idev); | ||
603 | if (ret < 0) { | ||
604 | dev_err(&pdev->dev, "Couldn't register the device.\n"); | ||
605 | goto error_remove_triggers; | ||
606 | } | ||
607 | |||
608 | return 0; | ||
609 | |||
610 | error_remove_triggers: | ||
611 | at91_adc_trigger_remove(idev); | ||
612 | error_unregister_buffer: | ||
613 | at91_adc_buffer_remove(idev); | ||
614 | error_disable_adc_clk: | ||
615 | clk_disable(st->adc_clk); | ||
616 | error_unprepare_adc_clk: | ||
617 | clk_unprepare(st->adc_clk); | ||
618 | error_free_adc_clk: | ||
619 | clk_put(st->adc_clk); | ||
620 | error_disable_clk: | ||
621 | clk_disable(st->clk); | ||
622 | error_unprepare_clk: | ||
623 | clk_unprepare(st->clk); | ||
624 | error_free_clk: | ||
625 | clk_put(st->clk); | ||
626 | error_free_irq: | ||
627 | free_irq(st->irq, idev); | ||
628 | error_unmap_reg: | ||
629 | iounmap(st->reg_base); | ||
630 | error_release_mem: | ||
631 | release_mem_region(res->start, resource_size(res)); | ||
632 | error_free_device: | ||
633 | iio_device_free(idev); | ||
634 | error_ret: | ||
635 | return ret; | ||
636 | } | ||
637 | |||
638 | static int __devexit at91_adc_remove(struct platform_device *pdev) | ||
639 | { | ||
640 | struct iio_dev *idev = platform_get_drvdata(pdev); | ||
641 | struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
642 | struct at91_adc_state *st = iio_priv(idev); | ||
643 | |||
644 | iio_device_unregister(idev); | ||
645 | at91_adc_trigger_remove(idev); | ||
646 | at91_adc_buffer_remove(idev); | ||
647 | clk_disable_unprepare(st->adc_clk); | ||
648 | clk_put(st->adc_clk); | ||
649 | clk_disable(st->clk); | ||
650 | clk_unprepare(st->clk); | ||
651 | clk_put(st->clk); | ||
652 | free_irq(st->irq, idev); | ||
653 | iounmap(st->reg_base); | ||
654 | release_mem_region(res->start, resource_size(res)); | ||
655 | iio_device_free(idev); | ||
656 | |||
657 | return 0; | ||
658 | } | ||
659 | |||
660 | static struct platform_driver at91_adc_driver = { | ||
661 | .probe = at91_adc_probe, | ||
662 | .remove = __devexit_p(at91_adc_remove), | ||
663 | .driver = { | ||
664 | .name = "at91_adc", | ||
665 | }, | ||
666 | }; | ||
667 | |||
668 | module_platform_driver(at91_adc_driver); | ||
669 | |||
670 | MODULE_LICENSE("GPL"); | ||
671 | MODULE_DESCRIPTION("Atmel AT91 ADC Driver"); | ||
672 | MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>"); | ||