blob: 1a968f34d67911d5029e97e1c67bbb15ebafb60a [file] [log] [blame]
Mark Brownd2bedfe2009-07-27 14:45:52 +01001/*
2 * wm831x-core.c -- Device access for Wolfson WM831x PMICs
3 *
4 * Copyright 2009 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/i2c.h>
Mark Brown7e9f9fd2009-07-27 14:45:54 +010018#include <linux/bcd.h>
19#include <linux/delay.h>
Mark Brownd2bedfe2009-07-27 14:45:52 +010020#include <linux/mfd/core.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090021#include <linux/slab.h>
Mark Brownd2bedfe2009-07-27 14:45:52 +010022
23#include <linux/mfd/wm831x/core.h>
24#include <linux/mfd/wm831x/pdata.h>
Mark Brown7d4d0a32009-07-27 14:45:53 +010025#include <linux/mfd/wm831x/irq.h>
Mark Brown7e9f9fd2009-07-27 14:45:54 +010026#include <linux/mfd/wm831x/auxadc.h>
Mark Brown6704e512009-07-27 14:45:56 +010027#include <linux/mfd/wm831x/otp.h>
Mark Brown698659d2009-07-27 14:45:57 +010028#include <linux/mfd/wm831x/regulator.h>
29
30/* Current settings - values are 2*2^(reg_val/4) microamps. These are
31 * exported since they are used by multiple drivers.
32 */
Mark Brown77169772009-11-30 13:24:18 +000033int wm831x_isinkv_values[WM831X_ISINK_MAX_ISEL + 1] = {
Mark Brown698659d2009-07-27 14:45:57 +010034 2,
35 2,
36 3,
37 3,
38 4,
39 5,
40 6,
41 7,
42 8,
43 10,
44 11,
45 13,
46 16,
47 19,
48 23,
49 27,
50 32,
51 38,
52 45,
53 54,
54 64,
55 76,
56 91,
57 108,
58 128,
59 152,
60 181,
61 215,
62 256,
63 304,
64 362,
65 431,
66 512,
67 609,
68 724,
69 861,
70 1024,
71 1218,
72 1448,
73 1722,
74 2048,
75 2435,
76 2896,
77 3444,
78 4096,
79 4871,
80 5793,
81 6889,
82 8192,
83 9742,
84 11585,
85 13777,
86 16384,
87 19484,
88 23170,
89 27554,
90};
91EXPORT_SYMBOL_GPL(wm831x_isinkv_values);
Mark Brownd2bedfe2009-07-27 14:45:52 +010092
93enum wm831x_parent {
Mark Brown894362f2009-10-01 15:41:04 +010094 WM8310 = 0x8310,
95 WM8311 = 0x8311,
96 WM8312 = 0x8312,
Mark Brownd4e0a892009-10-01 15:41:07 +010097 WM8320 = 0x8320,
Mark Brownd2bedfe2009-07-27 14:45:52 +010098};
99
100static int wm831x_reg_locked(struct wm831x *wm831x, unsigned short reg)
101{
102 if (!wm831x->locked)
103 return 0;
104
105 switch (reg) {
106 case WM831X_WATCHDOG:
107 case WM831X_DC4_CONTROL:
108 case WM831X_ON_PIN_CONTROL:
109 case WM831X_BACKUP_CHARGER_CONTROL:
110 case WM831X_CHARGER_CONTROL_1:
111 case WM831X_CHARGER_CONTROL_2:
112 return 1;
113
114 default:
115 return 0;
116 }
117}
118
119/**
120 * wm831x_reg_unlock: Unlock user keyed registers
121 *
122 * The WM831x has a user key preventing writes to particularly
123 * critical registers. This function locks those registers,
124 * allowing writes to them.
125 */
126void wm831x_reg_lock(struct wm831x *wm831x)
127{
128 int ret;
129
130 ret = wm831x_reg_write(wm831x, WM831X_SECURITY_KEY, 0);
131 if (ret == 0) {
132 dev_vdbg(wm831x->dev, "Registers locked\n");
133
134 mutex_lock(&wm831x->io_lock);
135 WARN_ON(wm831x->locked);
136 wm831x->locked = 1;
137 mutex_unlock(&wm831x->io_lock);
138 } else {
139 dev_err(wm831x->dev, "Failed to lock registers: %d\n", ret);
140 }
141
142}
143EXPORT_SYMBOL_GPL(wm831x_reg_lock);
144
145/**
146 * wm831x_reg_unlock: Unlock user keyed registers
147 *
148 * The WM831x has a user key preventing writes to particularly
149 * critical registers. This function locks those registers,
150 * preventing spurious writes.
151 */
152int wm831x_reg_unlock(struct wm831x *wm831x)
153{
154 int ret;
155
156 /* 0x9716 is the value required to unlock the registers */
157 ret = wm831x_reg_write(wm831x, WM831X_SECURITY_KEY, 0x9716);
158 if (ret == 0) {
159 dev_vdbg(wm831x->dev, "Registers unlocked\n");
160
161 mutex_lock(&wm831x->io_lock);
162 WARN_ON(!wm831x->locked);
163 wm831x->locked = 0;
164 mutex_unlock(&wm831x->io_lock);
165 }
166
167 return ret;
168}
169EXPORT_SYMBOL_GPL(wm831x_reg_unlock);
170
171static int wm831x_read(struct wm831x *wm831x, unsigned short reg,
172 int bytes, void *dest)
173{
174 int ret, i;
175 u16 *buf = dest;
176
177 BUG_ON(bytes % 2);
178 BUG_ON(bytes <= 0);
179
180 ret = wm831x->read_dev(wm831x, reg, bytes, dest);
181 if (ret < 0)
182 return ret;
183
184 for (i = 0; i < bytes / 2; i++) {
185 buf[i] = be16_to_cpu(buf[i]);
186
187 dev_vdbg(wm831x->dev, "Read %04x from R%d(0x%x)\n",
188 buf[i], reg + i, reg + i);
189 }
190
191 return 0;
192}
193
194/**
195 * wm831x_reg_read: Read a single WM831x register.
196 *
197 * @wm831x: Device to read from.
198 * @reg: Register to read.
199 */
200int wm831x_reg_read(struct wm831x *wm831x, unsigned short reg)
201{
202 unsigned short val;
203 int ret;
204
205 mutex_lock(&wm831x->io_lock);
206
207 ret = wm831x_read(wm831x, reg, 2, &val);
208
209 mutex_unlock(&wm831x->io_lock);
210
211 if (ret < 0)
212 return ret;
213 else
214 return val;
215}
216EXPORT_SYMBOL_GPL(wm831x_reg_read);
217
218/**
219 * wm831x_bulk_read: Read multiple WM831x registers
220 *
221 * @wm831x: Device to read from
222 * @reg: First register
223 * @count: Number of registers
224 * @buf: Buffer to fill.
225 */
226int wm831x_bulk_read(struct wm831x *wm831x, unsigned short reg,
227 int count, u16 *buf)
228{
229 int ret;
230
231 mutex_lock(&wm831x->io_lock);
232
233 ret = wm831x_read(wm831x, reg, count * 2, buf);
234
235 mutex_unlock(&wm831x->io_lock);
236
237 return ret;
238}
239EXPORT_SYMBOL_GPL(wm831x_bulk_read);
240
241static int wm831x_write(struct wm831x *wm831x, unsigned short reg,
242 int bytes, void *src)
243{
244 u16 *buf = src;
245 int i;
246
247 BUG_ON(bytes % 2);
248 BUG_ON(bytes <= 0);
249
250 for (i = 0; i < bytes / 2; i++) {
251 if (wm831x_reg_locked(wm831x, reg))
252 return -EPERM;
253
254 dev_vdbg(wm831x->dev, "Write %04x to R%d(0x%x)\n",
255 buf[i], reg + i, reg + i);
256
257 buf[i] = cpu_to_be16(buf[i]);
258 }
259
260 return wm831x->write_dev(wm831x, reg, bytes, src);
261}
262
263/**
264 * wm831x_reg_write: Write a single WM831x register.
265 *
266 * @wm831x: Device to write to.
267 * @reg: Register to write to.
268 * @val: Value to write.
269 */
270int wm831x_reg_write(struct wm831x *wm831x, unsigned short reg,
271 unsigned short val)
272{
273 int ret;
274
275 mutex_lock(&wm831x->io_lock);
276
277 ret = wm831x_write(wm831x, reg, 2, &val);
278
279 mutex_unlock(&wm831x->io_lock);
280
281 return ret;
282}
283EXPORT_SYMBOL_GPL(wm831x_reg_write);
284
285/**
286 * wm831x_set_bits: Set the value of a bitfield in a WM831x register
287 *
288 * @wm831x: Device to write to.
289 * @reg: Register to write to.
290 * @mask: Mask of bits to set.
291 * @val: Value to set (unshifted)
292 */
293int wm831x_set_bits(struct wm831x *wm831x, unsigned short reg,
294 unsigned short mask, unsigned short val)
295{
296 int ret;
297 u16 r;
298
299 mutex_lock(&wm831x->io_lock);
300
301 ret = wm831x_read(wm831x, reg, 2, &r);
302 if (ret < 0)
303 goto out;
304
305 r &= ~mask;
306 r |= val;
307
308 ret = wm831x_write(wm831x, reg, 2, &r);
309
310out:
311 mutex_unlock(&wm831x->io_lock);
312
313 return ret;
314}
315EXPORT_SYMBOL_GPL(wm831x_set_bits);
316
Mark Brown7e9f9fd2009-07-27 14:45:54 +0100317/**
318 * wm831x_auxadc_read: Read a value from the WM831x AUXADC
319 *
320 * @wm831x: Device to read from.
321 * @input: AUXADC input to read.
322 */
323int wm831x_auxadc_read(struct wm831x *wm831x, enum wm831x_auxadc input)
324{
Mark Brown7cc13922010-04-02 16:31:03 +0100325 int ret, src, irq_masked, timeout;
326
327 /* Are we using the interrupt? */
328 irq_masked = wm831x_reg_read(wm831x, WM831X_INTERRUPT_STATUS_1_MASK);
329 irq_masked &= WM831X_AUXADC_DATA_EINT;
Mark Brown7e9f9fd2009-07-27 14:45:54 +0100330
331 mutex_lock(&wm831x->auxadc_lock);
332
333 ret = wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL,
334 WM831X_AUX_ENA, WM831X_AUX_ENA);
335 if (ret < 0) {
336 dev_err(wm831x->dev, "Failed to enable AUXADC: %d\n", ret);
337 goto out;
338 }
339
340 /* We force a single source at present */
341 src = input;
342 ret = wm831x_reg_write(wm831x, WM831X_AUXADC_SOURCE,
343 1 << src);
344 if (ret < 0) {
345 dev_err(wm831x->dev, "Failed to set AUXADC source: %d\n", ret);
346 goto out;
347 }
348
Mark Brown7cc13922010-04-02 16:31:03 +0100349 /* Clear any notification from a very late arriving interrupt */
350 try_wait_for_completion(&wm831x->auxadc_done);
351
Mark Brown7e9f9fd2009-07-27 14:45:54 +0100352 ret = wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL,
353 WM831X_AUX_CVT_ENA, WM831X_AUX_CVT_ENA);
354 if (ret < 0) {
355 dev_err(wm831x->dev, "Failed to start AUXADC: %d\n", ret);
356 goto disable;
357 }
358
Mark Brown7cc13922010-04-02 16:31:03 +0100359 if (irq_masked) {
360 /* If we're not using interrupts then poll the
361 * interrupt status register */
362 timeout = 5;
363 while (timeout) {
364 msleep(1);
Mark Brown5051d412010-04-02 13:08:39 +0100365
Mark Brown7cc13922010-04-02 16:31:03 +0100366 ret = wm831x_reg_read(wm831x,
367 WM831X_INTERRUPT_STATUS_1);
368 if (ret < 0) {
369 dev_err(wm831x->dev,
370 "ISR 1 read failed: %d\n", ret);
371 goto disable;
372 }
Mark Brown7e9f9fd2009-07-27 14:45:54 +0100373
Mark Brown7cc13922010-04-02 16:31:03 +0100374 /* Did it complete? */
375 if (ret & WM831X_AUXADC_DATA_EINT) {
376 wm831x_reg_write(wm831x,
377 WM831X_INTERRUPT_STATUS_1,
378 WM831X_AUXADC_DATA_EINT);
379 break;
380 } else {
381 dev_err(wm831x->dev,
382 "AUXADC conversion timeout\n");
383 ret = -EBUSY;
384 goto disable;
385 }
386 }
387 } else {
388 /* If we are using interrupts then wait for the
389 * interrupt to complete. Use an extremely long
390 * timeout to handle situations with heavy load where
391 * the notification of the interrupt may be delayed by
392 * threaded IRQ handling. */
393 if (!wait_for_completion_timeout(&wm831x->auxadc_done,
394 msecs_to_jiffies(500))) {
395 dev_err(wm831x->dev, "Timed out waiting for AUXADC\n");
396 ret = -EBUSY;
397 goto disable;
398 }
Mark Brown7e9f9fd2009-07-27 14:45:54 +0100399 }
400
401 ret = wm831x_reg_read(wm831x, WM831X_AUXADC_DATA);
402 if (ret < 0) {
403 dev_err(wm831x->dev, "Failed to read AUXADC data: %d\n", ret);
404 } else {
405 src = ((ret & WM831X_AUX_DATA_SRC_MASK)
406 >> WM831X_AUX_DATA_SRC_SHIFT) - 1;
407
408 if (src == 14)
409 src = WM831X_AUX_CAL;
410
411 if (src != input) {
412 dev_err(wm831x->dev, "Data from source %d not %d\n",
413 src, input);
414 ret = -EINVAL;
415 } else {
416 ret &= WM831X_AUX_DATA_MASK;
417 }
418 }
419
420disable:
421 wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL, WM831X_AUX_ENA, 0);
422out:
423 mutex_unlock(&wm831x->auxadc_lock);
424 return ret;
425}
426EXPORT_SYMBOL_GPL(wm831x_auxadc_read);
427
Mark Brown473fe732010-02-23 11:08:06 +0000428static irqreturn_t wm831x_auxadc_irq(int irq, void *irq_data)
429{
430 struct wm831x *wm831x = irq_data;
431
432 complete(&wm831x->auxadc_done);
433
434 return IRQ_HANDLED;
435}
436
Mark Brown7e9f9fd2009-07-27 14:45:54 +0100437/**
438 * wm831x_auxadc_read_uv: Read a voltage from the WM831x AUXADC
439 *
440 * @wm831x: Device to read from.
441 * @input: AUXADC input to read.
442 */
443int wm831x_auxadc_read_uv(struct wm831x *wm831x, enum wm831x_auxadc input)
444{
445 int ret;
446
447 ret = wm831x_auxadc_read(wm831x, input);
448 if (ret < 0)
449 return ret;
450
451 ret *= 1465;
452
453 return ret;
454}
455EXPORT_SYMBOL_GPL(wm831x_auxadc_read_uv);
456
Mark Brownd2bedfe2009-07-27 14:45:52 +0100457static struct resource wm831x_dcdc1_resources[] = {
458 {
459 .start = WM831X_DC1_CONTROL_1,
460 .end = WM831X_DC1_DVS_CONTROL,
461 .flags = IORESOURCE_IO,
462 },
463 {
464 .name = "UV",
465 .start = WM831X_IRQ_UV_DC1,
466 .end = WM831X_IRQ_UV_DC1,
467 .flags = IORESOURCE_IRQ,
468 },
469 {
470 .name = "HC",
471 .start = WM831X_IRQ_HC_DC1,
472 .end = WM831X_IRQ_HC_DC1,
473 .flags = IORESOURCE_IRQ,
474 },
475};
476
477
478static struct resource wm831x_dcdc2_resources[] = {
479 {
480 .start = WM831X_DC2_CONTROL_1,
481 .end = WM831X_DC2_DVS_CONTROL,
482 .flags = IORESOURCE_IO,
483 },
484 {
485 .name = "UV",
486 .start = WM831X_IRQ_UV_DC2,
487 .end = WM831X_IRQ_UV_DC2,
488 .flags = IORESOURCE_IRQ,
489 },
490 {
491 .name = "HC",
492 .start = WM831X_IRQ_HC_DC2,
493 .end = WM831X_IRQ_HC_DC2,
494 .flags = IORESOURCE_IRQ,
495 },
496};
497
498static struct resource wm831x_dcdc3_resources[] = {
499 {
500 .start = WM831X_DC3_CONTROL_1,
501 .end = WM831X_DC3_SLEEP_CONTROL,
502 .flags = IORESOURCE_IO,
503 },
504 {
505 .name = "UV",
506 .start = WM831X_IRQ_UV_DC3,
507 .end = WM831X_IRQ_UV_DC3,
508 .flags = IORESOURCE_IRQ,
509 },
510};
511
512static struct resource wm831x_dcdc4_resources[] = {
513 {
514 .start = WM831X_DC4_CONTROL,
515 .end = WM831X_DC4_SLEEP_CONTROL,
516 .flags = IORESOURCE_IO,
517 },
518 {
519 .name = "UV",
520 .start = WM831X_IRQ_UV_DC4,
521 .end = WM831X_IRQ_UV_DC4,
522 .flags = IORESOURCE_IRQ,
523 },
524};
525
Mark Brownd4e0a892009-10-01 15:41:07 +0100526static struct resource wm8320_dcdc4_buck_resources[] = {
527 {
528 .start = WM831X_DC4_CONTROL,
529 .end = WM832X_DC4_SLEEP_CONTROL,
530 .flags = IORESOURCE_IO,
531 },
532 {
533 .name = "UV",
534 .start = WM831X_IRQ_UV_DC4,
535 .end = WM831X_IRQ_UV_DC4,
536 .flags = IORESOURCE_IRQ,
537 },
538};
539
Mark Brownd2bedfe2009-07-27 14:45:52 +0100540static struct resource wm831x_gpio_resources[] = {
541 {
542 .start = WM831X_IRQ_GPIO_1,
543 .end = WM831X_IRQ_GPIO_16,
544 .flags = IORESOURCE_IRQ,
545 },
546};
547
548static struct resource wm831x_isink1_resources[] = {
549 {
550 .start = WM831X_CURRENT_SINK_1,
551 .end = WM831X_CURRENT_SINK_1,
552 .flags = IORESOURCE_IO,
553 },
554 {
555 .start = WM831X_IRQ_CS1,
556 .end = WM831X_IRQ_CS1,
557 .flags = IORESOURCE_IRQ,
558 },
559};
560
561static struct resource wm831x_isink2_resources[] = {
562 {
563 .start = WM831X_CURRENT_SINK_2,
564 .end = WM831X_CURRENT_SINK_2,
565 .flags = IORESOURCE_IO,
566 },
567 {
568 .start = WM831X_IRQ_CS2,
569 .end = WM831X_IRQ_CS2,
570 .flags = IORESOURCE_IRQ,
571 },
572};
573
574static struct resource wm831x_ldo1_resources[] = {
575 {
576 .start = WM831X_LDO1_CONTROL,
577 .end = WM831X_LDO1_SLEEP_CONTROL,
578 .flags = IORESOURCE_IO,
579 },
580 {
581 .name = "UV",
582 .start = WM831X_IRQ_UV_LDO1,
583 .end = WM831X_IRQ_UV_LDO1,
584 .flags = IORESOURCE_IRQ,
585 },
586};
587
588static struct resource wm831x_ldo2_resources[] = {
589 {
590 .start = WM831X_LDO2_CONTROL,
591 .end = WM831X_LDO2_SLEEP_CONTROL,
592 .flags = IORESOURCE_IO,
593 },
594 {
595 .name = "UV",
596 .start = WM831X_IRQ_UV_LDO2,
597 .end = WM831X_IRQ_UV_LDO2,
598 .flags = IORESOURCE_IRQ,
599 },
600};
601
602static struct resource wm831x_ldo3_resources[] = {
603 {
604 .start = WM831X_LDO3_CONTROL,
605 .end = WM831X_LDO3_SLEEP_CONTROL,
606 .flags = IORESOURCE_IO,
607 },
608 {
609 .name = "UV",
610 .start = WM831X_IRQ_UV_LDO3,
611 .end = WM831X_IRQ_UV_LDO3,
612 .flags = IORESOURCE_IRQ,
613 },
614};
615
616static struct resource wm831x_ldo4_resources[] = {
617 {
618 .start = WM831X_LDO4_CONTROL,
619 .end = WM831X_LDO4_SLEEP_CONTROL,
620 .flags = IORESOURCE_IO,
621 },
622 {
623 .name = "UV",
624 .start = WM831X_IRQ_UV_LDO4,
625 .end = WM831X_IRQ_UV_LDO4,
626 .flags = IORESOURCE_IRQ,
627 },
628};
629
630static struct resource wm831x_ldo5_resources[] = {
631 {
632 .start = WM831X_LDO5_CONTROL,
633 .end = WM831X_LDO5_SLEEP_CONTROL,
634 .flags = IORESOURCE_IO,
635 },
636 {
637 .name = "UV",
638 .start = WM831X_IRQ_UV_LDO5,
639 .end = WM831X_IRQ_UV_LDO5,
640 .flags = IORESOURCE_IRQ,
641 },
642};
643
644static struct resource wm831x_ldo6_resources[] = {
645 {
646 .start = WM831X_LDO6_CONTROL,
647 .end = WM831X_LDO6_SLEEP_CONTROL,
648 .flags = IORESOURCE_IO,
649 },
650 {
651 .name = "UV",
652 .start = WM831X_IRQ_UV_LDO6,
653 .end = WM831X_IRQ_UV_LDO6,
654 .flags = IORESOURCE_IRQ,
655 },
656};
657
658static struct resource wm831x_ldo7_resources[] = {
659 {
660 .start = WM831X_LDO7_CONTROL,
661 .end = WM831X_LDO7_SLEEP_CONTROL,
662 .flags = IORESOURCE_IO,
663 },
664 {
665 .name = "UV",
666 .start = WM831X_IRQ_UV_LDO7,
667 .end = WM831X_IRQ_UV_LDO7,
668 .flags = IORESOURCE_IRQ,
669 },
670};
671
672static struct resource wm831x_ldo8_resources[] = {
673 {
674 .start = WM831X_LDO8_CONTROL,
675 .end = WM831X_LDO8_SLEEP_CONTROL,
676 .flags = IORESOURCE_IO,
677 },
678 {
679 .name = "UV",
680 .start = WM831X_IRQ_UV_LDO8,
681 .end = WM831X_IRQ_UV_LDO8,
682 .flags = IORESOURCE_IRQ,
683 },
684};
685
686static struct resource wm831x_ldo9_resources[] = {
687 {
688 .start = WM831X_LDO9_CONTROL,
689 .end = WM831X_LDO9_SLEEP_CONTROL,
690 .flags = IORESOURCE_IO,
691 },
692 {
693 .name = "UV",
694 .start = WM831X_IRQ_UV_LDO9,
695 .end = WM831X_IRQ_UV_LDO9,
696 .flags = IORESOURCE_IRQ,
697 },
698};
699
700static struct resource wm831x_ldo10_resources[] = {
701 {
702 .start = WM831X_LDO10_CONTROL,
703 .end = WM831X_LDO10_SLEEP_CONTROL,
704 .flags = IORESOURCE_IO,
705 },
706 {
707 .name = "UV",
708 .start = WM831X_IRQ_UV_LDO10,
709 .end = WM831X_IRQ_UV_LDO10,
710 .flags = IORESOURCE_IRQ,
711 },
712};
713
714static struct resource wm831x_ldo11_resources[] = {
715 {
716 .start = WM831X_LDO11_ON_CONTROL,
717 .end = WM831X_LDO11_SLEEP_CONTROL,
718 .flags = IORESOURCE_IO,
719 },
720};
721
722static struct resource wm831x_on_resources[] = {
723 {
724 .start = WM831X_IRQ_ON,
725 .end = WM831X_IRQ_ON,
726 .flags = IORESOURCE_IRQ,
727 },
728};
729
730
731static struct resource wm831x_power_resources[] = {
732 {
733 .name = "SYSLO",
734 .start = WM831X_IRQ_PPM_SYSLO,
735 .end = WM831X_IRQ_PPM_SYSLO,
736 .flags = IORESOURCE_IRQ,
737 },
738 {
739 .name = "PWR SRC",
740 .start = WM831X_IRQ_PPM_PWR_SRC,
741 .end = WM831X_IRQ_PPM_PWR_SRC,
742 .flags = IORESOURCE_IRQ,
743 },
744 {
745 .name = "USB CURR",
746 .start = WM831X_IRQ_PPM_USB_CURR,
747 .end = WM831X_IRQ_PPM_USB_CURR,
748 .flags = IORESOURCE_IRQ,
749 },
750 {
751 .name = "BATT HOT",
752 .start = WM831X_IRQ_CHG_BATT_HOT,
753 .end = WM831X_IRQ_CHG_BATT_HOT,
754 .flags = IORESOURCE_IRQ,
755 },
756 {
757 .name = "BATT COLD",
758 .start = WM831X_IRQ_CHG_BATT_COLD,
759 .end = WM831X_IRQ_CHG_BATT_COLD,
760 .flags = IORESOURCE_IRQ,
761 },
762 {
763 .name = "BATT FAIL",
764 .start = WM831X_IRQ_CHG_BATT_FAIL,
765 .end = WM831X_IRQ_CHG_BATT_FAIL,
766 .flags = IORESOURCE_IRQ,
767 },
768 {
769 .name = "OV",
770 .start = WM831X_IRQ_CHG_OV,
771 .end = WM831X_IRQ_CHG_OV,
772 .flags = IORESOURCE_IRQ,
773 },
774 {
775 .name = "END",
776 .start = WM831X_IRQ_CHG_END,
777 .end = WM831X_IRQ_CHG_END,
778 .flags = IORESOURCE_IRQ,
779 },
780 {
781 .name = "TO",
782 .start = WM831X_IRQ_CHG_TO,
783 .end = WM831X_IRQ_CHG_TO,
784 .flags = IORESOURCE_IRQ,
785 },
786 {
787 .name = "MODE",
788 .start = WM831X_IRQ_CHG_MODE,
789 .end = WM831X_IRQ_CHG_MODE,
790 .flags = IORESOURCE_IRQ,
791 },
792 {
793 .name = "START",
794 .start = WM831X_IRQ_CHG_START,
795 .end = WM831X_IRQ_CHG_START,
796 .flags = IORESOURCE_IRQ,
797 },
798};
799
800static struct resource wm831x_rtc_resources[] = {
801 {
802 .name = "PER",
803 .start = WM831X_IRQ_RTC_PER,
804 .end = WM831X_IRQ_RTC_PER,
805 .flags = IORESOURCE_IRQ,
806 },
807 {
808 .name = "ALM",
809 .start = WM831X_IRQ_RTC_ALM,
810 .end = WM831X_IRQ_RTC_ALM,
811 .flags = IORESOURCE_IRQ,
812 },
813};
814
815static struct resource wm831x_status1_resources[] = {
816 {
817 .start = WM831X_STATUS_LED_1,
818 .end = WM831X_STATUS_LED_1,
819 .flags = IORESOURCE_IO,
820 },
821};
822
823static struct resource wm831x_status2_resources[] = {
824 {
825 .start = WM831X_STATUS_LED_2,
826 .end = WM831X_STATUS_LED_2,
827 .flags = IORESOURCE_IO,
828 },
829};
830
831static struct resource wm831x_touch_resources[] = {
832 {
833 .name = "TCHPD",
834 .start = WM831X_IRQ_TCHPD,
835 .end = WM831X_IRQ_TCHPD,
836 .flags = IORESOURCE_IRQ,
837 },
838 {
839 .name = "TCHDATA",
840 .start = WM831X_IRQ_TCHDATA,
841 .end = WM831X_IRQ_TCHDATA,
842 .flags = IORESOURCE_IRQ,
843 },
844};
845
846static struct resource wm831x_wdt_resources[] = {
847 {
848 .start = WM831X_IRQ_WDOG_TO,
849 .end = WM831X_IRQ_WDOG_TO,
850 .flags = IORESOURCE_IRQ,
851 },
852};
853
854static struct mfd_cell wm8310_devs[] = {
855 {
Mark Brownc26964e2009-10-01 15:41:06 +0100856 .name = "wm831x-backup",
857 },
858 {
Mark Brownd2bedfe2009-07-27 14:45:52 +0100859 .name = "wm831x-buckv",
860 .id = 1,
861 .num_resources = ARRAY_SIZE(wm831x_dcdc1_resources),
862 .resources = wm831x_dcdc1_resources,
863 },
864 {
865 .name = "wm831x-buckv",
866 .id = 2,
867 .num_resources = ARRAY_SIZE(wm831x_dcdc2_resources),
868 .resources = wm831x_dcdc2_resources,
869 },
870 {
871 .name = "wm831x-buckp",
872 .id = 3,
873 .num_resources = ARRAY_SIZE(wm831x_dcdc3_resources),
874 .resources = wm831x_dcdc3_resources,
875 },
876 {
877 .name = "wm831x-boostp",
878 .id = 4,
879 .num_resources = ARRAY_SIZE(wm831x_dcdc4_resources),
880 .resources = wm831x_dcdc4_resources,
881 },
882 {
883 .name = "wm831x-epe",
884 .id = 1,
885 },
886 {
887 .name = "wm831x-epe",
888 .id = 2,
889 },
890 {
891 .name = "wm831x-gpio",
892 .num_resources = ARRAY_SIZE(wm831x_gpio_resources),
893 .resources = wm831x_gpio_resources,
894 },
895 {
896 .name = "wm831x-hwmon",
897 },
898 {
899 .name = "wm831x-isink",
900 .id = 1,
901 .num_resources = ARRAY_SIZE(wm831x_isink1_resources),
902 .resources = wm831x_isink1_resources,
903 },
904 {
905 .name = "wm831x-isink",
906 .id = 2,
907 .num_resources = ARRAY_SIZE(wm831x_isink2_resources),
908 .resources = wm831x_isink2_resources,
909 },
910 {
911 .name = "wm831x-ldo",
912 .id = 1,
913 .num_resources = ARRAY_SIZE(wm831x_ldo1_resources),
914 .resources = wm831x_ldo1_resources,
915 },
916 {
917 .name = "wm831x-ldo",
918 .id = 2,
919 .num_resources = ARRAY_SIZE(wm831x_ldo2_resources),
920 .resources = wm831x_ldo2_resources,
921 },
922 {
923 .name = "wm831x-ldo",
924 .id = 3,
925 .num_resources = ARRAY_SIZE(wm831x_ldo3_resources),
926 .resources = wm831x_ldo3_resources,
927 },
928 {
929 .name = "wm831x-ldo",
930 .id = 4,
931 .num_resources = ARRAY_SIZE(wm831x_ldo4_resources),
932 .resources = wm831x_ldo4_resources,
933 },
934 {
935 .name = "wm831x-ldo",
936 .id = 5,
937 .num_resources = ARRAY_SIZE(wm831x_ldo5_resources),
938 .resources = wm831x_ldo5_resources,
939 },
940 {
941 .name = "wm831x-ldo",
942 .id = 6,
943 .num_resources = ARRAY_SIZE(wm831x_ldo6_resources),
944 .resources = wm831x_ldo6_resources,
945 },
946 {
947 .name = "wm831x-aldo",
948 .id = 7,
949 .num_resources = ARRAY_SIZE(wm831x_ldo7_resources),
950 .resources = wm831x_ldo7_resources,
951 },
952 {
953 .name = "wm831x-aldo",
954 .id = 8,
955 .num_resources = ARRAY_SIZE(wm831x_ldo8_resources),
956 .resources = wm831x_ldo8_resources,
957 },
958 {
959 .name = "wm831x-aldo",
960 .id = 9,
961 .num_resources = ARRAY_SIZE(wm831x_ldo9_resources),
962 .resources = wm831x_ldo9_resources,
963 },
964 {
965 .name = "wm831x-aldo",
966 .id = 10,
967 .num_resources = ARRAY_SIZE(wm831x_ldo10_resources),
968 .resources = wm831x_ldo10_resources,
969 },
970 {
971 .name = "wm831x-alive-ldo",
972 .id = 11,
973 .num_resources = ARRAY_SIZE(wm831x_ldo11_resources),
974 .resources = wm831x_ldo11_resources,
975 },
976 {
977 .name = "wm831x-on",
978 .num_resources = ARRAY_SIZE(wm831x_on_resources),
979 .resources = wm831x_on_resources,
980 },
981 {
982 .name = "wm831x-power",
983 .num_resources = ARRAY_SIZE(wm831x_power_resources),
984 .resources = wm831x_power_resources,
985 },
986 {
987 .name = "wm831x-rtc",
988 .num_resources = ARRAY_SIZE(wm831x_rtc_resources),
989 .resources = wm831x_rtc_resources,
990 },
991 {
992 .name = "wm831x-status",
993 .id = 1,
994 .num_resources = ARRAY_SIZE(wm831x_status1_resources),
995 .resources = wm831x_status1_resources,
996 },
997 {
998 .name = "wm831x-status",
999 .id = 2,
1000 .num_resources = ARRAY_SIZE(wm831x_status2_resources),
1001 .resources = wm831x_status2_resources,
1002 },
1003 {
1004 .name = "wm831x-watchdog",
1005 .num_resources = ARRAY_SIZE(wm831x_wdt_resources),
1006 .resources = wm831x_wdt_resources,
1007 },
1008};
1009
1010static struct mfd_cell wm8311_devs[] = {
1011 {
Mark Brownc26964e2009-10-01 15:41:06 +01001012 .name = "wm831x-backup",
1013 },
1014 {
Mark Brownd2bedfe2009-07-27 14:45:52 +01001015 .name = "wm831x-buckv",
1016 .id = 1,
1017 .num_resources = ARRAY_SIZE(wm831x_dcdc1_resources),
1018 .resources = wm831x_dcdc1_resources,
1019 },
1020 {
1021 .name = "wm831x-buckv",
1022 .id = 2,
1023 .num_resources = ARRAY_SIZE(wm831x_dcdc2_resources),
1024 .resources = wm831x_dcdc2_resources,
1025 },
1026 {
1027 .name = "wm831x-buckp",
1028 .id = 3,
1029 .num_resources = ARRAY_SIZE(wm831x_dcdc3_resources),
1030 .resources = wm831x_dcdc3_resources,
1031 },
1032 {
1033 .name = "wm831x-boostp",
1034 .id = 4,
1035 .num_resources = ARRAY_SIZE(wm831x_dcdc4_resources),
1036 .resources = wm831x_dcdc4_resources,
1037 },
1038 {
1039 .name = "wm831x-epe",
1040 .id = 1,
1041 },
1042 {
1043 .name = "wm831x-epe",
1044 .id = 2,
1045 },
1046 {
1047 .name = "wm831x-gpio",
1048 .num_resources = ARRAY_SIZE(wm831x_gpio_resources),
1049 .resources = wm831x_gpio_resources,
1050 },
1051 {
1052 .name = "wm831x-hwmon",
1053 },
1054 {
1055 .name = "wm831x-isink",
1056 .id = 1,
1057 .num_resources = ARRAY_SIZE(wm831x_isink1_resources),
1058 .resources = wm831x_isink1_resources,
1059 },
1060 {
1061 .name = "wm831x-isink",
1062 .id = 2,
1063 .num_resources = ARRAY_SIZE(wm831x_isink2_resources),
1064 .resources = wm831x_isink2_resources,
1065 },
1066 {
1067 .name = "wm831x-ldo",
1068 .id = 1,
1069 .num_resources = ARRAY_SIZE(wm831x_ldo1_resources),
1070 .resources = wm831x_ldo1_resources,
1071 },
1072 {
1073 .name = "wm831x-ldo",
1074 .id = 2,
1075 .num_resources = ARRAY_SIZE(wm831x_ldo2_resources),
1076 .resources = wm831x_ldo2_resources,
1077 },
1078 {
1079 .name = "wm831x-ldo",
1080 .id = 3,
1081 .num_resources = ARRAY_SIZE(wm831x_ldo3_resources),
1082 .resources = wm831x_ldo3_resources,
1083 },
1084 {
1085 .name = "wm831x-ldo",
1086 .id = 4,
1087 .num_resources = ARRAY_SIZE(wm831x_ldo4_resources),
1088 .resources = wm831x_ldo4_resources,
1089 },
1090 {
1091 .name = "wm831x-ldo",
1092 .id = 5,
1093 .num_resources = ARRAY_SIZE(wm831x_ldo5_resources),
1094 .resources = wm831x_ldo5_resources,
1095 },
1096 {
1097 .name = "wm831x-aldo",
1098 .id = 7,
1099 .num_resources = ARRAY_SIZE(wm831x_ldo7_resources),
1100 .resources = wm831x_ldo7_resources,
1101 },
1102 {
1103 .name = "wm831x-alive-ldo",
1104 .id = 11,
1105 .num_resources = ARRAY_SIZE(wm831x_ldo11_resources),
1106 .resources = wm831x_ldo11_resources,
1107 },
1108 {
1109 .name = "wm831x-on",
1110 .num_resources = ARRAY_SIZE(wm831x_on_resources),
1111 .resources = wm831x_on_resources,
1112 },
1113 {
1114 .name = "wm831x-power",
1115 .num_resources = ARRAY_SIZE(wm831x_power_resources),
1116 .resources = wm831x_power_resources,
1117 },
1118 {
1119 .name = "wm831x-rtc",
1120 .num_resources = ARRAY_SIZE(wm831x_rtc_resources),
1121 .resources = wm831x_rtc_resources,
1122 },
1123 {
1124 .name = "wm831x-status",
1125 .id = 1,
1126 .num_resources = ARRAY_SIZE(wm831x_status1_resources),
1127 .resources = wm831x_status1_resources,
1128 },
1129 {
1130 .name = "wm831x-status",
1131 .id = 2,
1132 .num_resources = ARRAY_SIZE(wm831x_status2_resources),
1133 .resources = wm831x_status2_resources,
1134 },
1135 {
1136 .name = "wm831x-touch",
1137 .num_resources = ARRAY_SIZE(wm831x_touch_resources),
1138 .resources = wm831x_touch_resources,
1139 },
1140 {
1141 .name = "wm831x-watchdog",
1142 .num_resources = ARRAY_SIZE(wm831x_wdt_resources),
1143 .resources = wm831x_wdt_resources,
1144 },
1145};
1146
1147static struct mfd_cell wm8312_devs[] = {
1148 {
Mark Brownc26964e2009-10-01 15:41:06 +01001149 .name = "wm831x-backup",
1150 },
1151 {
Mark Brownd2bedfe2009-07-27 14:45:52 +01001152 .name = "wm831x-buckv",
1153 .id = 1,
1154 .num_resources = ARRAY_SIZE(wm831x_dcdc1_resources),
1155 .resources = wm831x_dcdc1_resources,
1156 },
1157 {
1158 .name = "wm831x-buckv",
1159 .id = 2,
1160 .num_resources = ARRAY_SIZE(wm831x_dcdc2_resources),
1161 .resources = wm831x_dcdc2_resources,
1162 },
1163 {
1164 .name = "wm831x-buckp",
1165 .id = 3,
1166 .num_resources = ARRAY_SIZE(wm831x_dcdc3_resources),
1167 .resources = wm831x_dcdc3_resources,
1168 },
1169 {
1170 .name = "wm831x-boostp",
1171 .id = 4,
1172 .num_resources = ARRAY_SIZE(wm831x_dcdc4_resources),
1173 .resources = wm831x_dcdc4_resources,
1174 },
1175 {
1176 .name = "wm831x-epe",
1177 .id = 1,
1178 },
1179 {
1180 .name = "wm831x-epe",
1181 .id = 2,
1182 },
1183 {
1184 .name = "wm831x-gpio",
1185 .num_resources = ARRAY_SIZE(wm831x_gpio_resources),
1186 .resources = wm831x_gpio_resources,
1187 },
1188 {
1189 .name = "wm831x-hwmon",
1190 },
1191 {
1192 .name = "wm831x-isink",
1193 .id = 1,
1194 .num_resources = ARRAY_SIZE(wm831x_isink1_resources),
1195 .resources = wm831x_isink1_resources,
1196 },
1197 {
1198 .name = "wm831x-isink",
1199 .id = 2,
1200 .num_resources = ARRAY_SIZE(wm831x_isink2_resources),
1201 .resources = wm831x_isink2_resources,
1202 },
1203 {
1204 .name = "wm831x-ldo",
1205 .id = 1,
1206 .num_resources = ARRAY_SIZE(wm831x_ldo1_resources),
1207 .resources = wm831x_ldo1_resources,
1208 },
1209 {
1210 .name = "wm831x-ldo",
1211 .id = 2,
1212 .num_resources = ARRAY_SIZE(wm831x_ldo2_resources),
1213 .resources = wm831x_ldo2_resources,
1214 },
1215 {
1216 .name = "wm831x-ldo",
1217 .id = 3,
1218 .num_resources = ARRAY_SIZE(wm831x_ldo3_resources),
1219 .resources = wm831x_ldo3_resources,
1220 },
1221 {
1222 .name = "wm831x-ldo",
1223 .id = 4,
1224 .num_resources = ARRAY_SIZE(wm831x_ldo4_resources),
1225 .resources = wm831x_ldo4_resources,
1226 },
1227 {
1228 .name = "wm831x-ldo",
1229 .id = 5,
1230 .num_resources = ARRAY_SIZE(wm831x_ldo5_resources),
1231 .resources = wm831x_ldo5_resources,
1232 },
1233 {
1234 .name = "wm831x-ldo",
1235 .id = 6,
1236 .num_resources = ARRAY_SIZE(wm831x_ldo6_resources),
1237 .resources = wm831x_ldo6_resources,
1238 },
1239 {
1240 .name = "wm831x-aldo",
1241 .id = 7,
1242 .num_resources = ARRAY_SIZE(wm831x_ldo7_resources),
1243 .resources = wm831x_ldo7_resources,
1244 },
1245 {
1246 .name = "wm831x-aldo",
1247 .id = 8,
1248 .num_resources = ARRAY_SIZE(wm831x_ldo8_resources),
1249 .resources = wm831x_ldo8_resources,
1250 },
1251 {
1252 .name = "wm831x-aldo",
1253 .id = 9,
1254 .num_resources = ARRAY_SIZE(wm831x_ldo9_resources),
1255 .resources = wm831x_ldo9_resources,
1256 },
1257 {
1258 .name = "wm831x-aldo",
1259 .id = 10,
1260 .num_resources = ARRAY_SIZE(wm831x_ldo10_resources),
1261 .resources = wm831x_ldo10_resources,
1262 },
1263 {
1264 .name = "wm831x-alive-ldo",
1265 .id = 11,
1266 .num_resources = ARRAY_SIZE(wm831x_ldo11_resources),
1267 .resources = wm831x_ldo11_resources,
1268 },
1269 {
1270 .name = "wm831x-on",
1271 .num_resources = ARRAY_SIZE(wm831x_on_resources),
1272 .resources = wm831x_on_resources,
1273 },
1274 {
1275 .name = "wm831x-power",
1276 .num_resources = ARRAY_SIZE(wm831x_power_resources),
1277 .resources = wm831x_power_resources,
1278 },
1279 {
1280 .name = "wm831x-rtc",
1281 .num_resources = ARRAY_SIZE(wm831x_rtc_resources),
1282 .resources = wm831x_rtc_resources,
1283 },
1284 {
1285 .name = "wm831x-status",
1286 .id = 1,
1287 .num_resources = ARRAY_SIZE(wm831x_status1_resources),
1288 .resources = wm831x_status1_resources,
1289 },
1290 {
1291 .name = "wm831x-status",
1292 .id = 2,
1293 .num_resources = ARRAY_SIZE(wm831x_status2_resources),
1294 .resources = wm831x_status2_resources,
1295 },
1296 {
1297 .name = "wm831x-touch",
1298 .num_resources = ARRAY_SIZE(wm831x_touch_resources),
1299 .resources = wm831x_touch_resources,
1300 },
1301 {
1302 .name = "wm831x-watchdog",
1303 .num_resources = ARRAY_SIZE(wm831x_wdt_resources),
1304 .resources = wm831x_wdt_resources,
1305 },
1306};
1307
Mark Brownd4e0a892009-10-01 15:41:07 +01001308static struct mfd_cell wm8320_devs[] = {
1309 {
1310 .name = "wm831x-backup",
1311 },
1312 {
1313 .name = "wm831x-buckv",
1314 .id = 1,
1315 .num_resources = ARRAY_SIZE(wm831x_dcdc1_resources),
1316 .resources = wm831x_dcdc1_resources,
1317 },
1318 {
1319 .name = "wm831x-buckv",
1320 .id = 2,
1321 .num_resources = ARRAY_SIZE(wm831x_dcdc2_resources),
1322 .resources = wm831x_dcdc2_resources,
1323 },
1324 {
1325 .name = "wm831x-buckp",
1326 .id = 3,
1327 .num_resources = ARRAY_SIZE(wm831x_dcdc3_resources),
1328 .resources = wm831x_dcdc3_resources,
1329 },
1330 {
1331 .name = "wm831x-buckp",
1332 .id = 4,
1333 .num_resources = ARRAY_SIZE(wm8320_dcdc4_buck_resources),
1334 .resources = wm8320_dcdc4_buck_resources,
1335 },
1336 {
1337 .name = "wm831x-gpio",
1338 .num_resources = ARRAY_SIZE(wm831x_gpio_resources),
1339 .resources = wm831x_gpio_resources,
1340 },
1341 {
1342 .name = "wm831x-hwmon",
1343 },
1344 {
1345 .name = "wm831x-ldo",
1346 .id = 1,
1347 .num_resources = ARRAY_SIZE(wm831x_ldo1_resources),
1348 .resources = wm831x_ldo1_resources,
1349 },
1350 {
1351 .name = "wm831x-ldo",
1352 .id = 2,
1353 .num_resources = ARRAY_SIZE(wm831x_ldo2_resources),
1354 .resources = wm831x_ldo2_resources,
1355 },
1356 {
1357 .name = "wm831x-ldo",
1358 .id = 3,
1359 .num_resources = ARRAY_SIZE(wm831x_ldo3_resources),
1360 .resources = wm831x_ldo3_resources,
1361 },
1362 {
1363 .name = "wm831x-ldo",
1364 .id = 4,
1365 .num_resources = ARRAY_SIZE(wm831x_ldo4_resources),
1366 .resources = wm831x_ldo4_resources,
1367 },
1368 {
1369 .name = "wm831x-ldo",
1370 .id = 5,
1371 .num_resources = ARRAY_SIZE(wm831x_ldo5_resources),
1372 .resources = wm831x_ldo5_resources,
1373 },
1374 {
1375 .name = "wm831x-ldo",
1376 .id = 6,
1377 .num_resources = ARRAY_SIZE(wm831x_ldo6_resources),
1378 .resources = wm831x_ldo6_resources,
1379 },
1380 {
1381 .name = "wm831x-aldo",
1382 .id = 7,
1383 .num_resources = ARRAY_SIZE(wm831x_ldo7_resources),
1384 .resources = wm831x_ldo7_resources,
1385 },
1386 {
1387 .name = "wm831x-aldo",
1388 .id = 8,
1389 .num_resources = ARRAY_SIZE(wm831x_ldo8_resources),
1390 .resources = wm831x_ldo8_resources,
1391 },
1392 {
1393 .name = "wm831x-aldo",
1394 .id = 9,
1395 .num_resources = ARRAY_SIZE(wm831x_ldo9_resources),
1396 .resources = wm831x_ldo9_resources,
1397 },
1398 {
1399 .name = "wm831x-aldo",
1400 .id = 10,
1401 .num_resources = ARRAY_SIZE(wm831x_ldo10_resources),
1402 .resources = wm831x_ldo10_resources,
1403 },
1404 {
1405 .name = "wm831x-alive-ldo",
1406 .id = 11,
1407 .num_resources = ARRAY_SIZE(wm831x_ldo11_resources),
1408 .resources = wm831x_ldo11_resources,
1409 },
1410 {
1411 .name = "wm831x-on",
1412 .num_resources = ARRAY_SIZE(wm831x_on_resources),
1413 .resources = wm831x_on_resources,
1414 },
1415 {
1416 .name = "wm831x-rtc",
1417 .num_resources = ARRAY_SIZE(wm831x_rtc_resources),
1418 .resources = wm831x_rtc_resources,
1419 },
1420 {
1421 .name = "wm831x-status",
1422 .id = 1,
1423 .num_resources = ARRAY_SIZE(wm831x_status1_resources),
1424 .resources = wm831x_status1_resources,
1425 },
1426 {
1427 .name = "wm831x-status",
1428 .id = 2,
1429 .num_resources = ARRAY_SIZE(wm831x_status2_resources),
1430 .resources = wm831x_status2_resources,
1431 },
1432 {
1433 .name = "wm831x-watchdog",
1434 .num_resources = ARRAY_SIZE(wm831x_wdt_resources),
1435 .resources = wm831x_wdt_resources,
1436 },
1437};
1438
Mark Brown63aed852009-07-27 14:45:55 +01001439static struct mfd_cell backlight_devs[] = {
1440 {
1441 .name = "wm831x-backlight",
1442 },
1443};
1444
Mark Brownd2bedfe2009-07-27 14:45:52 +01001445/*
1446 * Instantiate the generic non-control parts of the device.
1447 */
1448static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
1449{
1450 struct wm831x_pdata *pdata = wm831x->dev->platform_data;
1451 int rev;
1452 enum wm831x_parent parent;
1453 int ret;
1454
1455 mutex_init(&wm831x->io_lock);
1456 mutex_init(&wm831x->key_lock);
Mark Brown7e9f9fd2009-07-27 14:45:54 +01001457 mutex_init(&wm831x->auxadc_lock);
Mark Brown473fe732010-02-23 11:08:06 +00001458 init_completion(&wm831x->auxadc_done);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001459 dev_set_drvdata(wm831x->dev, wm831x);
1460
1461 ret = wm831x_reg_read(wm831x, WM831X_PARENT_ID);
1462 if (ret < 0) {
1463 dev_err(wm831x->dev, "Failed to read parent ID: %d\n", ret);
1464 goto err;
1465 }
1466 if (ret != 0x6204) {
1467 dev_err(wm831x->dev, "Device is not a WM831x: ID %x\n", ret);
1468 ret = -EINVAL;
1469 goto err;
1470 }
1471
1472 ret = wm831x_reg_read(wm831x, WM831X_REVISION);
1473 if (ret < 0) {
1474 dev_err(wm831x->dev, "Failed to read revision: %d\n", ret);
1475 goto err;
1476 }
1477 rev = (ret & WM831X_PARENT_REV_MASK) >> WM831X_PARENT_REV_SHIFT;
1478
1479 ret = wm831x_reg_read(wm831x, WM831X_RESET_ID);
1480 if (ret < 0) {
1481 dev_err(wm831x->dev, "Failed to read device ID: %d\n", ret);
1482 goto err;
1483 }
1484
Mark Brown894362f2009-10-01 15:41:04 +01001485 /* Some engineering samples do not have the ID set, rely on
1486 * the device being registered correctly.
1487 */
1488 if (ret == 0) {
1489 dev_info(wm831x->dev, "Device is an engineering sample\n");
1490 ret = id;
1491 }
1492
Mark Brownd2bedfe2009-07-27 14:45:52 +01001493 switch (ret) {
Mark Brown894362f2009-10-01 15:41:04 +01001494 case WM8310:
Mark Brownd2bedfe2009-07-27 14:45:52 +01001495 parent = WM8310;
Mark Brown6f2ecaa2009-10-01 15:41:05 +01001496 wm831x->num_gpio = 16;
Mark Brownb03b4d7c2010-04-08 10:02:39 +02001497 wm831x->charger_irq_wake = 1;
Mark Brownf92e8f82010-02-17 18:45:25 +00001498 if (rev > 0) {
1499 wm831x->has_gpio_ena = 1;
1500 wm831x->has_cs_sts = 1;
1501 }
1502
Mark Brown894362f2009-10-01 15:41:04 +01001503 dev_info(wm831x->dev, "WM8310 revision %c\n", 'A' + rev);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001504 break;
1505
Mark Brown894362f2009-10-01 15:41:04 +01001506 case WM8311:
Mark Brownd2bedfe2009-07-27 14:45:52 +01001507 parent = WM8311;
Mark Brown6f2ecaa2009-10-01 15:41:05 +01001508 wm831x->num_gpio = 16;
Mark Brownb03b4d7c2010-04-08 10:02:39 +02001509 wm831x->charger_irq_wake = 1;
Mark Brownf92e8f82010-02-17 18:45:25 +00001510 if (rev > 0) {
1511 wm831x->has_gpio_ena = 1;
1512 wm831x->has_cs_sts = 1;
1513 }
1514
Mark Brown894362f2009-10-01 15:41:04 +01001515 dev_info(wm831x->dev, "WM8311 revision %c\n", 'A' + rev);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001516 break;
1517
Mark Brown894362f2009-10-01 15:41:04 +01001518 case WM8312:
Mark Brownd2bedfe2009-07-27 14:45:52 +01001519 parent = WM8312;
Mark Brown6f2ecaa2009-10-01 15:41:05 +01001520 wm831x->num_gpio = 16;
Mark Brownb03b4d7c2010-04-08 10:02:39 +02001521 wm831x->charger_irq_wake = 1;
Mark Brownf92e8f82010-02-17 18:45:25 +00001522 if (rev > 0) {
1523 wm831x->has_gpio_ena = 1;
1524 wm831x->has_cs_sts = 1;
1525 }
1526
Mark Brown894362f2009-10-01 15:41:04 +01001527 dev_info(wm831x->dev, "WM8312 revision %c\n", 'A' + rev);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001528 break;
1529
Mark Brownd4e0a892009-10-01 15:41:07 +01001530 case WM8320:
1531 parent = WM8320;
1532 wm831x->num_gpio = 12;
1533 dev_info(wm831x->dev, "WM8320 revision %c\n", 'A' + rev);
1534 break;
1535
Mark Brownd2bedfe2009-07-27 14:45:52 +01001536 default:
1537 dev_err(wm831x->dev, "Unknown WM831x device %04x\n", ret);
1538 ret = -EINVAL;
1539 goto err;
1540 }
1541
1542 /* This will need revisiting in future but is OK for all
1543 * current parts.
1544 */
1545 if (parent != id)
Mark Brown894362f2009-10-01 15:41:04 +01001546 dev_warn(wm831x->dev, "Device was registered as a WM%lx\n",
Mark Brownd2bedfe2009-07-27 14:45:52 +01001547 id);
1548
1549 /* Bootstrap the user key */
1550 ret = wm831x_reg_read(wm831x, WM831X_SECURITY_KEY);
1551 if (ret < 0) {
1552 dev_err(wm831x->dev, "Failed to read security key: %d\n", ret);
1553 goto err;
1554 }
1555 if (ret != 0) {
1556 dev_warn(wm831x->dev, "Security key had non-zero value %x\n",
1557 ret);
1558 wm831x_reg_write(wm831x, WM831X_SECURITY_KEY, 0);
1559 }
1560 wm831x->locked = 1;
1561
1562 if (pdata && pdata->pre_init) {
1563 ret = pdata->pre_init(wm831x);
1564 if (ret != 0) {
1565 dev_err(wm831x->dev, "pre_init() failed: %d\n", ret);
1566 goto err;
1567 }
1568 }
1569
Mark Brown7d4d0a32009-07-27 14:45:53 +01001570 ret = wm831x_irq_init(wm831x, irq);
1571 if (ret != 0)
1572 goto err;
1573
Mark Brown473fe732010-02-23 11:08:06 +00001574 if (wm831x->irq_base) {
1575 ret = request_threaded_irq(wm831x->irq_base +
1576 WM831X_IRQ_AUXADC_DATA,
1577 NULL, wm831x_auxadc_irq, 0,
1578 "auxadc", wm831x);
1579 if (ret < 0)
1580 dev_err(wm831x->dev, "AUXADC IRQ request failed: %d\n",
1581 ret);
1582 }
1583
Mark Brownd2bedfe2009-07-27 14:45:52 +01001584 /* The core device is up, instantiate the subdevices. */
1585 switch (parent) {
1586 case WM8310:
1587 ret = mfd_add_devices(wm831x->dev, -1,
1588 wm8310_devs, ARRAY_SIZE(wm8310_devs),
Mark Brown5fb4d382009-11-11 16:10:22 +00001589 NULL, wm831x->irq_base);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001590 break;
1591
1592 case WM8311:
1593 ret = mfd_add_devices(wm831x->dev, -1,
1594 wm8311_devs, ARRAY_SIZE(wm8311_devs),
Mark Brown5fb4d382009-11-11 16:10:22 +00001595 NULL, wm831x->irq_base);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001596 break;
1597
1598 case WM8312:
1599 ret = mfd_add_devices(wm831x->dev, -1,
1600 wm8312_devs, ARRAY_SIZE(wm8312_devs),
Mark Brown5fb4d382009-11-11 16:10:22 +00001601 NULL, wm831x->irq_base);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001602 break;
1603
Mark Brownd4e0a892009-10-01 15:41:07 +01001604 case WM8320:
1605 ret = mfd_add_devices(wm831x->dev, -1,
1606 wm8320_devs, ARRAY_SIZE(wm8320_devs),
1607 NULL, 0);
1608 break;
1609
Mark Brownd2bedfe2009-07-27 14:45:52 +01001610 default:
1611 /* If this happens the bus probe function is buggy */
1612 BUG();
1613 }
1614
1615 if (ret != 0) {
1616 dev_err(wm831x->dev, "Failed to add children\n");
Mark Brown7d4d0a32009-07-27 14:45:53 +01001617 goto err_irq;
Mark Brownd2bedfe2009-07-27 14:45:52 +01001618 }
1619
Mark Brown63aed852009-07-27 14:45:55 +01001620 if (pdata && pdata->backlight) {
1621 /* Treat errors as non-critical */
1622 ret = mfd_add_devices(wm831x->dev, -1, backlight_devs,
Mark Brown5fb4d382009-11-11 16:10:22 +00001623 ARRAY_SIZE(backlight_devs), NULL,
1624 wm831x->irq_base);
Mark Brown63aed852009-07-27 14:45:55 +01001625 if (ret < 0)
1626 dev_err(wm831x->dev, "Failed to add backlight: %d\n",
1627 ret);
1628 }
1629
Mark Brown6704e512009-07-27 14:45:56 +01001630 wm831x_otp_init(wm831x);
1631
Mark Brownd2bedfe2009-07-27 14:45:52 +01001632 if (pdata && pdata->post_init) {
1633 ret = pdata->post_init(wm831x);
1634 if (ret != 0) {
1635 dev_err(wm831x->dev, "post_init() failed: %d\n", ret);
Mark Brown7d4d0a32009-07-27 14:45:53 +01001636 goto err_irq;
Mark Brownd2bedfe2009-07-27 14:45:52 +01001637 }
1638 }
1639
1640 return 0;
1641
Mark Brown7d4d0a32009-07-27 14:45:53 +01001642err_irq:
1643 wm831x_irq_exit(wm831x);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001644err:
1645 mfd_remove_devices(wm831x->dev);
1646 kfree(wm831x);
1647 return ret;
1648}
1649
1650static void wm831x_device_exit(struct wm831x *wm831x)
1651{
Mark Brown6704e512009-07-27 14:45:56 +01001652 wm831x_otp_exit(wm831x);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001653 mfd_remove_devices(wm831x->dev);
Mark Brown473fe732010-02-23 11:08:06 +00001654 if (wm831x->irq_base)
1655 free_irq(wm831x->irq_base + WM831X_IRQ_AUXADC_DATA, wm831x);
Mark Brown7d4d0a32009-07-27 14:45:53 +01001656 wm831x_irq_exit(wm831x);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001657 kfree(wm831x);
1658}
1659
Mark Brownb03b4d7c2010-04-08 10:02:39 +02001660static int wm831x_device_suspend(struct wm831x *wm831x)
1661{
1662 int reg, mask;
1663
1664 /* If the charger IRQs are a wake source then make sure we ack
1665 * them even if they're not actively being used (eg, no power
1666 * driver or no IRQ line wired up) then acknowledge the
1667 * interrupts otherwise suspend won't last very long.
1668 */
1669 if (wm831x->charger_irq_wake) {
1670 reg = wm831x_reg_read(wm831x, WM831X_INTERRUPT_STATUS_2_MASK);
1671
1672 mask = WM831X_CHG_BATT_HOT_EINT |
1673 WM831X_CHG_BATT_COLD_EINT |
1674 WM831X_CHG_BATT_FAIL_EINT |
1675 WM831X_CHG_OV_EINT | WM831X_CHG_END_EINT |
1676 WM831X_CHG_TO_EINT | WM831X_CHG_MODE_EINT |
1677 WM831X_CHG_START_EINT;
1678
1679 /* If any of the interrupts are masked read the statuses */
1680 if (reg & mask)
1681 reg = wm831x_reg_read(wm831x,
1682 WM831X_INTERRUPT_STATUS_2);
1683
1684 if (reg & mask) {
1685 dev_info(wm831x->dev,
1686 "Acknowledging masked charger IRQs: %x\n",
1687 reg & mask);
1688 wm831x_reg_write(wm831x, WM831X_INTERRUPT_STATUS_2,
1689 reg & mask);
1690 }
1691 }
1692
1693 return 0;
1694}
1695
Mark Brownd2bedfe2009-07-27 14:45:52 +01001696static int wm831x_i2c_read_device(struct wm831x *wm831x, unsigned short reg,
1697 int bytes, void *dest)
1698{
1699 struct i2c_client *i2c = wm831x->control_data;
1700 int ret;
1701 u16 r = cpu_to_be16(reg);
1702
1703 ret = i2c_master_send(i2c, (unsigned char *)&r, 2);
1704 if (ret < 0)
1705 return ret;
1706 if (ret != 2)
1707 return -EIO;
1708
1709 ret = i2c_master_recv(i2c, dest, bytes);
1710 if (ret < 0)
1711 return ret;
1712 if (ret != bytes)
1713 return -EIO;
1714 return 0;
1715}
1716
1717/* Currently we allocate the write buffer on the stack; this is OK for
1718 * small writes - if we need to do large writes this will need to be
1719 * revised.
1720 */
1721static int wm831x_i2c_write_device(struct wm831x *wm831x, unsigned short reg,
1722 int bytes, void *src)
1723{
1724 struct i2c_client *i2c = wm831x->control_data;
1725 unsigned char msg[bytes + 2];
1726 int ret;
1727
1728 reg = cpu_to_be16(reg);
1729 memcpy(&msg[0], &reg, 2);
1730 memcpy(&msg[2], src, bytes);
1731
1732 ret = i2c_master_send(i2c, msg, bytes + 2);
1733 if (ret < 0)
1734 return ret;
1735 if (ret < bytes + 2)
1736 return -EIO;
1737
1738 return 0;
1739}
1740
1741static int wm831x_i2c_probe(struct i2c_client *i2c,
1742 const struct i2c_device_id *id)
1743{
1744 struct wm831x *wm831x;
1745
1746 wm831x = kzalloc(sizeof(struct wm831x), GFP_KERNEL);
1747 if (wm831x == NULL) {
1748 kfree(i2c);
1749 return -ENOMEM;
1750 }
1751
1752 i2c_set_clientdata(i2c, wm831x);
1753 wm831x->dev = &i2c->dev;
1754 wm831x->control_data = i2c;
1755 wm831x->read_dev = wm831x_i2c_read_device;
1756 wm831x->write_dev = wm831x_i2c_write_device;
1757
1758 return wm831x_device_init(wm831x, id->driver_data, i2c->irq);
1759}
1760
1761static int wm831x_i2c_remove(struct i2c_client *i2c)
1762{
1763 struct wm831x *wm831x = i2c_get_clientdata(i2c);
1764
1765 wm831x_device_exit(wm831x);
1766
1767 return 0;
1768}
1769
Mark Brownb03b4d7c2010-04-08 10:02:39 +02001770static int wm831x_i2c_suspend(struct i2c_client *i2c, pm_message_t mesg)
1771{
1772 struct wm831x *wm831x = i2c_get_clientdata(i2c);
1773
1774 return wm831x_device_suspend(wm831x);
1775}
1776
Mark Brownd2bedfe2009-07-27 14:45:52 +01001777static const struct i2c_device_id wm831x_i2c_id[] = {
1778 { "wm8310", WM8310 },
1779 { "wm8311", WM8311 },
1780 { "wm8312", WM8312 },
Mark Brownd4e0a892009-10-01 15:41:07 +01001781 { "wm8320", WM8320 },
Mark Brownd2bedfe2009-07-27 14:45:52 +01001782 { }
1783};
1784MODULE_DEVICE_TABLE(i2c, wm831x_i2c_id);
1785
1786
1787static struct i2c_driver wm831x_i2c_driver = {
1788 .driver = {
1789 .name = "wm831x",
1790 .owner = THIS_MODULE,
1791 },
1792 .probe = wm831x_i2c_probe,
1793 .remove = wm831x_i2c_remove,
Mark Brownb03b4d7c2010-04-08 10:02:39 +02001794 .suspend = wm831x_i2c_suspend,
Mark Brownd2bedfe2009-07-27 14:45:52 +01001795 .id_table = wm831x_i2c_id,
1796};
1797
1798static int __init wm831x_i2c_init(void)
1799{
1800 int ret;
1801
1802 ret = i2c_add_driver(&wm831x_i2c_driver);
1803 if (ret != 0)
1804 pr_err("Failed to register wm831x I2C driver: %d\n", ret);
1805
1806 return ret;
1807}
1808subsys_initcall(wm831x_i2c_init);
1809
1810static void __exit wm831x_i2c_exit(void)
1811{
1812 i2c_del_driver(&wm831x_i2c_driver);
1813}
1814module_exit(wm831x_i2c_exit);
1815
1816MODULE_DESCRIPTION("I2C support for the WM831X AudioPlus PMIC");
1817MODULE_LICENSE("GPL");
1818MODULE_AUTHOR("Mark Brown");