diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/mfd/wm831x-core.c | 101 |
1 files changed, 101 insertions, 0 deletions
diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c index eb63d22160d1..42bef1dd2ca1 100644 --- a/drivers/mfd/wm831x-core.c +++ b/drivers/mfd/wm831x-core.c | |||
@@ -15,11 +15,14 @@ | |||
15 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <linux/i2c.h> | 17 | #include <linux/i2c.h> |
18 | #include <linux/bcd.h> | ||
19 | #include <linux/delay.h> | ||
18 | #include <linux/mfd/core.h> | 20 | #include <linux/mfd/core.h> |
19 | 21 | ||
20 | #include <linux/mfd/wm831x/core.h> | 22 | #include <linux/mfd/wm831x/core.h> |
21 | #include <linux/mfd/wm831x/pdata.h> | 23 | #include <linux/mfd/wm831x/pdata.h> |
22 | #include <linux/mfd/wm831x/irq.h> | 24 | #include <linux/mfd/wm831x/irq.h> |
25 | #include <linux/mfd/wm831x/auxadc.h> | ||
23 | 26 | ||
24 | enum wm831x_parent { | 27 | enum wm831x_parent { |
25 | WM8310 = 0, | 28 | WM8310 = 0, |
@@ -244,6 +247,103 @@ out: | |||
244 | } | 247 | } |
245 | EXPORT_SYMBOL_GPL(wm831x_set_bits); | 248 | EXPORT_SYMBOL_GPL(wm831x_set_bits); |
246 | 249 | ||
250 | /** | ||
251 | * wm831x_auxadc_read: Read a value from the WM831x AUXADC | ||
252 | * | ||
253 | * @wm831x: Device to read from. | ||
254 | * @input: AUXADC input to read. | ||
255 | */ | ||
256 | int wm831x_auxadc_read(struct wm831x *wm831x, enum wm831x_auxadc input) | ||
257 | { | ||
258 | int tries = 10; | ||
259 | int ret, src; | ||
260 | |||
261 | mutex_lock(&wm831x->auxadc_lock); | ||
262 | |||
263 | ret = wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL, | ||
264 | WM831X_AUX_ENA, WM831X_AUX_ENA); | ||
265 | if (ret < 0) { | ||
266 | dev_err(wm831x->dev, "Failed to enable AUXADC: %d\n", ret); | ||
267 | goto out; | ||
268 | } | ||
269 | |||
270 | /* We force a single source at present */ | ||
271 | src = input; | ||
272 | ret = wm831x_reg_write(wm831x, WM831X_AUXADC_SOURCE, | ||
273 | 1 << src); | ||
274 | if (ret < 0) { | ||
275 | dev_err(wm831x->dev, "Failed to set AUXADC source: %d\n", ret); | ||
276 | goto out; | ||
277 | } | ||
278 | |||
279 | ret = wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL, | ||
280 | WM831X_AUX_CVT_ENA, WM831X_AUX_CVT_ENA); | ||
281 | if (ret < 0) { | ||
282 | dev_err(wm831x->dev, "Failed to start AUXADC: %d\n", ret); | ||
283 | goto disable; | ||
284 | } | ||
285 | |||
286 | do { | ||
287 | msleep(1); | ||
288 | |||
289 | ret = wm831x_reg_read(wm831x, WM831X_AUXADC_CONTROL); | ||
290 | if (ret < 0) | ||
291 | ret = WM831X_AUX_CVT_ENA; | ||
292 | } while ((ret & WM831X_AUX_CVT_ENA) && --tries); | ||
293 | |||
294 | if (ret & WM831X_AUX_CVT_ENA) { | ||
295 | dev_err(wm831x->dev, "Timed out reading AUXADC\n"); | ||
296 | ret = -EBUSY; | ||
297 | goto disable; | ||
298 | } | ||
299 | |||
300 | ret = wm831x_reg_read(wm831x, WM831X_AUXADC_DATA); | ||
301 | if (ret < 0) { | ||
302 | dev_err(wm831x->dev, "Failed to read AUXADC data: %d\n", ret); | ||
303 | } else { | ||
304 | src = ((ret & WM831X_AUX_DATA_SRC_MASK) | ||
305 | >> WM831X_AUX_DATA_SRC_SHIFT) - 1; | ||
306 | |||
307 | if (src == 14) | ||
308 | src = WM831X_AUX_CAL; | ||
309 | |||
310 | if (src != input) { | ||
311 | dev_err(wm831x->dev, "Data from source %d not %d\n", | ||
312 | src, input); | ||
313 | ret = -EINVAL; | ||
314 | } else { | ||
315 | ret &= WM831X_AUX_DATA_MASK; | ||
316 | } | ||
317 | } | ||
318 | |||
319 | disable: | ||
320 | wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL, WM831X_AUX_ENA, 0); | ||
321 | out: | ||
322 | mutex_unlock(&wm831x->auxadc_lock); | ||
323 | return ret; | ||
324 | } | ||
325 | EXPORT_SYMBOL_GPL(wm831x_auxadc_read); | ||
326 | |||
327 | /** | ||
328 | * wm831x_auxadc_read_uv: Read a voltage from the WM831x AUXADC | ||
329 | * | ||
330 | * @wm831x: Device to read from. | ||
331 | * @input: AUXADC input to read. | ||
332 | */ | ||
333 | int wm831x_auxadc_read_uv(struct wm831x *wm831x, enum wm831x_auxadc input) | ||
334 | { | ||
335 | int ret; | ||
336 | |||
337 | ret = wm831x_auxadc_read(wm831x, input); | ||
338 | if (ret < 0) | ||
339 | return ret; | ||
340 | |||
341 | ret *= 1465; | ||
342 | |||
343 | return ret; | ||
344 | } | ||
345 | EXPORT_SYMBOL_GPL(wm831x_auxadc_read_uv); | ||
346 | |||
247 | static struct resource wm831x_dcdc1_resources[] = { | 347 | static struct resource wm831x_dcdc1_resources[] = { |
248 | { | 348 | { |
249 | .start = WM831X_DC1_CONTROL_1, | 349 | .start = WM831X_DC1_CONTROL_1, |
@@ -1084,6 +1184,7 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) | |||
1084 | 1184 | ||
1085 | mutex_init(&wm831x->io_lock); | 1185 | mutex_init(&wm831x->io_lock); |
1086 | mutex_init(&wm831x->key_lock); | 1186 | mutex_init(&wm831x->key_lock); |
1187 | mutex_init(&wm831x->auxadc_lock); | ||
1087 | dev_set_drvdata(wm831x->dev, wm831x); | 1188 | dev_set_drvdata(wm831x->dev, wm831x); |
1088 | 1189 | ||
1089 | ret = wm831x_reg_read(wm831x, WM831X_PARENT_ID); | 1190 | ret = wm831x_reg_read(wm831x, WM831X_PARENT_ID); |