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