diff options
author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2011-06-02 14:18:53 -0400 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2011-07-31 17:28:20 -0400 |
commit | e69b6de181167a132eee7c38c7e4b47dea3d8e49 (patch) | |
tree | 2c0fceff037fa76791155bbbf6bec8d75a5bbc1e /drivers/mfd | |
parent | c1a82780b41e78f31636c49279ce940afe60a453 (diff) |
mfd: Refactor wm831x AUXADC handling into a separate file
In preparation for some additional work on the wm831x AUXADC code move the
support into a separate file. This is a simple code motion patch, there
should be no functional changes.
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers/mfd')
-rw-r--r-- | drivers/mfd/Makefile | 1 | ||||
-rw-r--r-- | drivers/mfd/wm831x-auxadc.c | 199 | ||||
-rw-r--r-- | drivers/mfd/wm831x-core.c | 167 |
3 files changed, 201 insertions, 166 deletions
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 22a280fcb705..0889f53c8b02 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile | |||
@@ -23,6 +23,7 @@ obj-$(CONFIG_MFD_TC6393XB) += tc6393xb.o tmio_core.o | |||
23 | 23 | ||
24 | obj-$(CONFIG_MFD_WM8400) += wm8400-core.o | 24 | obj-$(CONFIG_MFD_WM8400) += wm8400-core.o |
25 | wm831x-objs := wm831x-core.o wm831x-irq.o wm831x-otp.o | 25 | wm831x-objs := wm831x-core.o wm831x-irq.o wm831x-otp.o |
26 | wm831x-objs += wm831x-auxadc.o | ||
26 | obj-$(CONFIG_MFD_WM831X) += wm831x.o | 27 | obj-$(CONFIG_MFD_WM831X) += wm831x.o |
27 | obj-$(CONFIG_MFD_WM831X_I2C) += wm831x-i2c.o | 28 | obj-$(CONFIG_MFD_WM831X_I2C) += wm831x-i2c.o |
28 | obj-$(CONFIG_MFD_WM831X_SPI) += wm831x-spi.o | 29 | obj-$(CONFIG_MFD_WM831X_SPI) += wm831x-spi.o |
diff --git a/drivers/mfd/wm831x-auxadc.c b/drivers/mfd/wm831x-auxadc.c new file mode 100644 index 000000000000..2fc9531b243d --- /dev/null +++ b/drivers/mfd/wm831x-auxadc.c | |||
@@ -0,0 +1,199 @@ | |||
1 | /* | ||
2 | * wm831x-auxadc.c -- AUXADC for Wolfson WM831x PMICs | ||
3 | * | ||
4 | * Copyright 2009-2011 Wolfson Microelectronics PLC. | ||
5 | * | ||
6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/delay.h> | ||
18 | #include <linux/mfd/core.h> | ||
19 | #include <linux/slab.h> | ||
20 | |||
21 | #include <linux/mfd/wm831x/core.h> | ||
22 | #include <linux/mfd/wm831x/pdata.h> | ||
23 | #include <linux/mfd/wm831x/irq.h> | ||
24 | #include <linux/mfd/wm831x/auxadc.h> | ||
25 | #include <linux/mfd/wm831x/otp.h> | ||
26 | #include <linux/mfd/wm831x/regulator.h> | ||
27 | |||
28 | /** | ||
29 | * wm831x_auxadc_read: Read a value from the WM831x AUXADC | ||
30 | * | ||
31 | * @wm831x: Device to read from. | ||
32 | * @input: AUXADC input to read. | ||
33 | */ | ||
34 | int wm831x_auxadc_read(struct wm831x *wm831x, enum wm831x_auxadc input) | ||
35 | { | ||
36 | int ret, src, irq_masked, timeout; | ||
37 | |||
38 | /* Are we using the interrupt? */ | ||
39 | irq_masked = wm831x_reg_read(wm831x, WM831X_INTERRUPT_STATUS_1_MASK); | ||
40 | irq_masked &= WM831X_AUXADC_DATA_EINT; | ||
41 | |||
42 | mutex_lock(&wm831x->auxadc_lock); | ||
43 | |||
44 | ret = wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL, | ||
45 | WM831X_AUX_ENA, WM831X_AUX_ENA); | ||
46 | if (ret < 0) { | ||
47 | dev_err(wm831x->dev, "Failed to enable AUXADC: %d\n", ret); | ||
48 | goto out; | ||
49 | } | ||
50 | |||
51 | /* We force a single source at present */ | ||
52 | src = input; | ||
53 | ret = wm831x_reg_write(wm831x, WM831X_AUXADC_SOURCE, | ||
54 | 1 << src); | ||
55 | if (ret < 0) { | ||
56 | dev_err(wm831x->dev, "Failed to set AUXADC source: %d\n", ret); | ||
57 | goto out; | ||
58 | } | ||
59 | |||
60 | /* Clear any notification from a very late arriving interrupt */ | ||
61 | try_wait_for_completion(&wm831x->auxadc_done); | ||
62 | |||
63 | ret = wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL, | ||
64 | WM831X_AUX_CVT_ENA, WM831X_AUX_CVT_ENA); | ||
65 | if (ret < 0) { | ||
66 | dev_err(wm831x->dev, "Failed to start AUXADC: %d\n", ret); | ||
67 | goto disable; | ||
68 | } | ||
69 | |||
70 | if (irq_masked) { | ||
71 | /* If we're not using interrupts then poll the | ||
72 | * interrupt status register */ | ||
73 | timeout = 5; | ||
74 | while (timeout) { | ||
75 | msleep(1); | ||
76 | |||
77 | ret = wm831x_reg_read(wm831x, | ||
78 | WM831X_INTERRUPT_STATUS_1); | ||
79 | if (ret < 0) { | ||
80 | dev_err(wm831x->dev, | ||
81 | "ISR 1 read failed: %d\n", ret); | ||
82 | goto disable; | ||
83 | } | ||
84 | |||
85 | /* Did it complete? */ | ||
86 | if (ret & WM831X_AUXADC_DATA_EINT) { | ||
87 | wm831x_reg_write(wm831x, | ||
88 | WM831X_INTERRUPT_STATUS_1, | ||
89 | WM831X_AUXADC_DATA_EINT); | ||
90 | break; | ||
91 | } else { | ||
92 | dev_err(wm831x->dev, | ||
93 | "AUXADC conversion timeout\n"); | ||
94 | ret = -EBUSY; | ||
95 | goto disable; | ||
96 | } | ||
97 | } | ||
98 | |||
99 | ret = wm831x_reg_read(wm831x, WM831X_AUXADC_DATA); | ||
100 | if (ret < 0) { | ||
101 | dev_err(wm831x->dev, | ||
102 | "Failed to read AUXADC data: %d\n", ret); | ||
103 | goto disable; | ||
104 | } | ||
105 | |||
106 | wm831x->auxadc_data = ret; | ||
107 | |||
108 | } else { | ||
109 | /* If we are using interrupts then wait for the | ||
110 | * interrupt to complete. Use an extremely long | ||
111 | * timeout to handle situations with heavy load where | ||
112 | * the notification of the interrupt may be delayed by | ||
113 | * threaded IRQ handling. */ | ||
114 | if (!wait_for_completion_timeout(&wm831x->auxadc_done, | ||
115 | msecs_to_jiffies(500))) { | ||
116 | dev_err(wm831x->dev, "Timed out waiting for AUXADC\n"); | ||
117 | ret = -EBUSY; | ||
118 | goto disable; | ||
119 | } | ||
120 | } | ||
121 | |||
122 | src = ((wm831x->auxadc_data & WM831X_AUX_DATA_SRC_MASK) | ||
123 | >> WM831X_AUX_DATA_SRC_SHIFT) - 1; | ||
124 | |||
125 | if (src == 14) | ||
126 | src = WM831X_AUX_CAL; | ||
127 | |||
128 | if (src != input) { | ||
129 | dev_err(wm831x->dev, "Data from source %d not %d\n", | ||
130 | src, input); | ||
131 | ret = -EINVAL; | ||
132 | } else { | ||
133 | ret = wm831x->auxadc_data & WM831X_AUX_DATA_MASK; | ||
134 | } | ||
135 | |||
136 | disable: | ||
137 | wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL, WM831X_AUX_ENA, 0); | ||
138 | out: | ||
139 | mutex_unlock(&wm831x->auxadc_lock); | ||
140 | return ret; | ||
141 | } | ||
142 | EXPORT_SYMBOL_GPL(wm831x_auxadc_read); | ||
143 | |||
144 | static irqreturn_t wm831x_auxadc_irq(int irq, void *irq_data) | ||
145 | { | ||
146 | struct wm831x *wm831x = irq_data; | ||
147 | int ret; | ||
148 | |||
149 | ret = wm831x_reg_read(wm831x, WM831X_AUXADC_DATA); | ||
150 | if (ret < 0) { | ||
151 | dev_err(wm831x->dev, | ||
152 | "Failed to read AUXADC data: %d\n", ret); | ||
153 | wm831x->auxadc_data = 0xffff; | ||
154 | } else { | ||
155 | wm831x->auxadc_data = ret; | ||
156 | } | ||
157 | |||
158 | complete(&wm831x->auxadc_done); | ||
159 | |||
160 | return IRQ_HANDLED; | ||
161 | } | ||
162 | |||
163 | /** | ||
164 | * wm831x_auxadc_read_uv: Read a voltage from the WM831x AUXADC | ||
165 | * | ||
166 | * @wm831x: Device to read from. | ||
167 | * @input: AUXADC input to read. | ||
168 | */ | ||
169 | int wm831x_auxadc_read_uv(struct wm831x *wm831x, enum wm831x_auxadc input) | ||
170 | { | ||
171 | int ret; | ||
172 | |||
173 | ret = wm831x_auxadc_read(wm831x, input); | ||
174 | if (ret < 0) | ||
175 | return ret; | ||
176 | |||
177 | ret *= 1465; | ||
178 | |||
179 | return ret; | ||
180 | } | ||
181 | EXPORT_SYMBOL_GPL(wm831x_auxadc_read_uv); | ||
182 | |||
183 | void wm831x_auxadc_init(struct wm831x *wm831x) | ||
184 | { | ||
185 | int ret; | ||
186 | |||
187 | mutex_init(&wm831x->auxadc_lock); | ||
188 | init_completion(&wm831x->auxadc_done); | ||
189 | |||
190 | if (wm831x->irq_base) { | ||
191 | ret = request_threaded_irq(wm831x->irq_base + | ||
192 | WM831X_IRQ_AUXADC_DATA, | ||
193 | NULL, wm831x_auxadc_irq, 0, | ||
194 | "auxadc", wm831x); | ||
195 | if (ret < 0) | ||
196 | dev_err(wm831x->dev, "AUXADC IRQ request failed: %d\n", | ||
197 | ret); | ||
198 | } | ||
199 | } | ||
diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c index 480abc18f9f3..772fe584f3b8 100644 --- a/drivers/mfd/wm831x-core.c +++ b/drivers/mfd/wm831x-core.c | |||
@@ -306,161 +306,6 @@ out: | |||
306 | } | 306 | } |
307 | EXPORT_SYMBOL_GPL(wm831x_set_bits); | 307 | EXPORT_SYMBOL_GPL(wm831x_set_bits); |
308 | 308 | ||
309 | /** | ||
310 | * wm831x_auxadc_read: Read a value from the WM831x AUXADC | ||
311 | * | ||
312 | * @wm831x: Device to read from. | ||
313 | * @input: AUXADC input to read. | ||
314 | */ | ||
315 | int wm831x_auxadc_read(struct wm831x *wm831x, enum wm831x_auxadc input) | ||
316 | { | ||
317 | int ret, src, irq_masked, timeout; | ||
318 | |||
319 | /* Are we using the interrupt? */ | ||
320 | irq_masked = wm831x_reg_read(wm831x, WM831X_INTERRUPT_STATUS_1_MASK); | ||
321 | irq_masked &= WM831X_AUXADC_DATA_EINT; | ||
322 | |||
323 | mutex_lock(&wm831x->auxadc_lock); | ||
324 | |||
325 | ret = wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL, | ||
326 | WM831X_AUX_ENA, WM831X_AUX_ENA); | ||
327 | if (ret < 0) { | ||
328 | dev_err(wm831x->dev, "Failed to enable AUXADC: %d\n", ret); | ||
329 | goto out; | ||
330 | } | ||
331 | |||
332 | /* We force a single source at present */ | ||
333 | src = input; | ||
334 | ret = wm831x_reg_write(wm831x, WM831X_AUXADC_SOURCE, | ||
335 | 1 << src); | ||
336 | if (ret < 0) { | ||
337 | dev_err(wm831x->dev, "Failed to set AUXADC source: %d\n", ret); | ||
338 | goto out; | ||
339 | } | ||
340 | |||
341 | /* Clear any notification from a very late arriving interrupt */ | ||
342 | try_wait_for_completion(&wm831x->auxadc_done); | ||
343 | |||
344 | ret = wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL, | ||
345 | WM831X_AUX_CVT_ENA, WM831X_AUX_CVT_ENA); | ||
346 | if (ret < 0) { | ||
347 | dev_err(wm831x->dev, "Failed to start AUXADC: %d\n", ret); | ||
348 | goto disable; | ||
349 | } | ||
350 | |||
351 | if (irq_masked) { | ||
352 | /* If we're not using interrupts then poll the | ||
353 | * interrupt status register */ | ||
354 | timeout = 5; | ||
355 | while (timeout) { | ||
356 | msleep(1); | ||
357 | |||
358 | ret = wm831x_reg_read(wm831x, | ||
359 | WM831X_INTERRUPT_STATUS_1); | ||
360 | if (ret < 0) { | ||
361 | dev_err(wm831x->dev, | ||
362 | "ISR 1 read failed: %d\n", ret); | ||
363 | goto disable; | ||
364 | } | ||
365 | |||
366 | /* Did it complete? */ | ||
367 | if (ret & WM831X_AUXADC_DATA_EINT) { | ||
368 | wm831x_reg_write(wm831x, | ||
369 | WM831X_INTERRUPT_STATUS_1, | ||
370 | WM831X_AUXADC_DATA_EINT); | ||
371 | break; | ||
372 | } else { | ||
373 | dev_err(wm831x->dev, | ||
374 | "AUXADC conversion timeout\n"); | ||
375 | ret = -EBUSY; | ||
376 | goto disable; | ||
377 | } | ||
378 | } | ||
379 | |||
380 | ret = wm831x_reg_read(wm831x, WM831X_AUXADC_DATA); | ||
381 | if (ret < 0) { | ||
382 | dev_err(wm831x->dev, | ||
383 | "Failed to read AUXADC data: %d\n", ret); | ||
384 | goto disable; | ||
385 | } | ||
386 | |||
387 | wm831x->auxadc_data = ret; | ||
388 | |||
389 | } else { | ||
390 | /* If we are using interrupts then wait for the | ||
391 | * interrupt to complete. Use an extremely long | ||
392 | * timeout to handle situations with heavy load where | ||
393 | * the notification of the interrupt may be delayed by | ||
394 | * threaded IRQ handling. */ | ||
395 | if (!wait_for_completion_timeout(&wm831x->auxadc_done, | ||
396 | msecs_to_jiffies(500))) { | ||
397 | dev_err(wm831x->dev, "Timed out waiting for AUXADC\n"); | ||
398 | ret = -EBUSY; | ||
399 | goto disable; | ||
400 | } | ||
401 | } | ||
402 | |||
403 | src = ((wm831x->auxadc_data & WM831X_AUX_DATA_SRC_MASK) | ||
404 | >> WM831X_AUX_DATA_SRC_SHIFT) - 1; | ||
405 | |||
406 | if (src == 14) | ||
407 | src = WM831X_AUX_CAL; | ||
408 | |||
409 | if (src != input) { | ||
410 | dev_err(wm831x->dev, "Data from source %d not %d\n", | ||
411 | src, input); | ||
412 | ret = -EINVAL; | ||
413 | } else { | ||
414 | ret = wm831x->auxadc_data & WM831X_AUX_DATA_MASK; | ||
415 | } | ||
416 | |||
417 | disable: | ||
418 | wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL, WM831X_AUX_ENA, 0); | ||
419 | out: | ||
420 | mutex_unlock(&wm831x->auxadc_lock); | ||
421 | return ret; | ||
422 | } | ||
423 | EXPORT_SYMBOL_GPL(wm831x_auxadc_read); | ||
424 | |||
425 | static irqreturn_t wm831x_auxadc_irq(int irq, void *irq_data) | ||
426 | { | ||
427 | struct wm831x *wm831x = irq_data; | ||
428 | int ret; | ||
429 | |||
430 | ret = wm831x_reg_read(wm831x, WM831X_AUXADC_DATA); | ||
431 | if (ret < 0) { | ||
432 | dev_err(wm831x->dev, | ||
433 | "Failed to read AUXADC data: %d\n", ret); | ||
434 | wm831x->auxadc_data = 0xffff; | ||
435 | } else { | ||
436 | wm831x->auxadc_data = ret; | ||
437 | } | ||
438 | |||
439 | complete(&wm831x->auxadc_done); | ||
440 | |||
441 | return IRQ_HANDLED; | ||
442 | } | ||
443 | |||
444 | /** | ||
445 | * wm831x_auxadc_read_uv: Read a voltage from the WM831x AUXADC | ||
446 | * | ||
447 | * @wm831x: Device to read from. | ||
448 | * @input: AUXADC input to read. | ||
449 | */ | ||
450 | int wm831x_auxadc_read_uv(struct wm831x *wm831x, enum wm831x_auxadc input) | ||
451 | { | ||
452 | int ret; | ||
453 | |||
454 | ret = wm831x_auxadc_read(wm831x, input); | ||
455 | if (ret < 0) | ||
456 | return ret; | ||
457 | |||
458 | ret *= 1465; | ||
459 | |||
460 | return ret; | ||
461 | } | ||
462 | EXPORT_SYMBOL_GPL(wm831x_auxadc_read_uv); | ||
463 | |||
464 | static struct resource wm831x_dcdc1_resources[] = { | 309 | static struct resource wm831x_dcdc1_resources[] = { |
465 | { | 310 | { |
466 | .start = WM831X_DC1_CONTROL_1, | 311 | .start = WM831X_DC1_CONTROL_1, |
@@ -1447,8 +1292,6 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) | |||
1447 | 1292 | ||
1448 | mutex_init(&wm831x->io_lock); | 1293 | mutex_init(&wm831x->io_lock); |
1449 | mutex_init(&wm831x->key_lock); | 1294 | mutex_init(&wm831x->key_lock); |
1450 | mutex_init(&wm831x->auxadc_lock); | ||
1451 | init_completion(&wm831x->auxadc_done); | ||
1452 | dev_set_drvdata(wm831x->dev, wm831x); | 1295 | dev_set_drvdata(wm831x->dev, wm831x); |
1453 | 1296 | ||
1454 | ret = wm831x_reg_read(wm831x, WM831X_PARENT_ID); | 1297 | ret = wm831x_reg_read(wm831x, WM831X_PARENT_ID); |
@@ -1603,15 +1446,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) | |||
1603 | if (ret != 0) | 1446 | if (ret != 0) |
1604 | goto err; | 1447 | goto err; |
1605 | 1448 | ||
1606 | if (wm831x->irq_base) { | 1449 | wm831x_auxadc_init(wm831x); |
1607 | ret = request_threaded_irq(wm831x->irq_base + | ||
1608 | WM831X_IRQ_AUXADC_DATA, | ||
1609 | NULL, wm831x_auxadc_irq, 0, | ||
1610 | "auxadc", wm831x); | ||
1611 | if (ret < 0) | ||
1612 | dev_err(wm831x->dev, "AUXADC IRQ request failed: %d\n", | ||
1613 | ret); | ||
1614 | } | ||
1615 | 1450 | ||
1616 | /* The core device is up, instantiate the subdevices. */ | 1451 | /* The core device is up, instantiate the subdevices. */ |
1617 | switch (parent) { | 1452 | switch (parent) { |