blob: 4b2021af1d9646be71d5a257c9adc0ded9b8052d [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>
21
22#include <linux/mfd/wm831x/core.h>
23#include <linux/mfd/wm831x/pdata.h>
Mark Brown7d4d0a32009-07-27 14:45:53 +010024#include <linux/mfd/wm831x/irq.h>
Mark Brown7e9f9fd2009-07-27 14:45:54 +010025#include <linux/mfd/wm831x/auxadc.h>
Mark Brown6704e512009-07-27 14:45:56 +010026#include <linux/mfd/wm831x/otp.h>
Mark Brown698659d2009-07-27 14:45:57 +010027#include <linux/mfd/wm831x/regulator.h>
28
29/* Current settings - values are 2*2^(reg_val/4) microamps. These are
30 * exported since they are used by multiple drivers.
31 */
Mark Brown77169772009-11-30 13:24:18 +000032int wm831x_isinkv_values[WM831X_ISINK_MAX_ISEL + 1] = {
Mark Brown698659d2009-07-27 14:45:57 +010033 2,
34 2,
35 3,
36 3,
37 4,
38 5,
39 6,
40 7,
41 8,
42 10,
43 11,
44 13,
45 16,
46 19,
47 23,
48 27,
49 32,
50 38,
51 45,
52 54,
53 64,
54 76,
55 91,
56 108,
57 128,
58 152,
59 181,
60 215,
61 256,
62 304,
63 362,
64 431,
65 512,
66 609,
67 724,
68 861,
69 1024,
70 1218,
71 1448,
72 1722,
73 2048,
74 2435,
75 2896,
76 3444,
77 4096,
78 4871,
79 5793,
80 6889,
81 8192,
82 9742,
83 11585,
84 13777,
85 16384,
86 19484,
87 23170,
88 27554,
89};
90EXPORT_SYMBOL_GPL(wm831x_isinkv_values);
Mark Brownd2bedfe2009-07-27 14:45:52 +010091
92enum wm831x_parent {
Mark Brown894362f2009-10-01 15:41:04 +010093 WM8310 = 0x8310,
94 WM8311 = 0x8311,
95 WM8312 = 0x8312,
Mark Brownd4e0a892009-10-01 15:41:07 +010096 WM8320 = 0x8320,
Mark Brownd2bedfe2009-07-27 14:45:52 +010097};
98
99static int wm831x_reg_locked(struct wm831x *wm831x, unsigned short reg)
100{
101 if (!wm831x->locked)
102 return 0;
103
104 switch (reg) {
105 case WM831X_WATCHDOG:
106 case WM831X_DC4_CONTROL:
107 case WM831X_ON_PIN_CONTROL:
108 case WM831X_BACKUP_CHARGER_CONTROL:
109 case WM831X_CHARGER_CONTROL_1:
110 case WM831X_CHARGER_CONTROL_2:
111 return 1;
112
113 default:
114 return 0;
115 }
116}
117
118/**
119 * wm831x_reg_unlock: Unlock user keyed registers
120 *
121 * The WM831x has a user key preventing writes to particularly
122 * critical registers. This function locks those registers,
123 * allowing writes to them.
124 */
125void wm831x_reg_lock(struct wm831x *wm831x)
126{
127 int ret;
128
129 ret = wm831x_reg_write(wm831x, WM831X_SECURITY_KEY, 0);
130 if (ret == 0) {
131 dev_vdbg(wm831x->dev, "Registers locked\n");
132
133 mutex_lock(&wm831x->io_lock);
134 WARN_ON(wm831x->locked);
135 wm831x->locked = 1;
136 mutex_unlock(&wm831x->io_lock);
137 } else {
138 dev_err(wm831x->dev, "Failed to lock registers: %d\n", ret);
139 }
140
141}
142EXPORT_SYMBOL_GPL(wm831x_reg_lock);
143
144/**
145 * wm831x_reg_unlock: Unlock user keyed registers
146 *
147 * The WM831x has a user key preventing writes to particularly
148 * critical registers. This function locks those registers,
149 * preventing spurious writes.
150 */
151int wm831x_reg_unlock(struct wm831x *wm831x)
152{
153 int ret;
154
155 /* 0x9716 is the value required to unlock the registers */
156 ret = wm831x_reg_write(wm831x, WM831X_SECURITY_KEY, 0x9716);
157 if (ret == 0) {
158 dev_vdbg(wm831x->dev, "Registers unlocked\n");
159
160 mutex_lock(&wm831x->io_lock);
161 WARN_ON(!wm831x->locked);
162 wm831x->locked = 0;
163 mutex_unlock(&wm831x->io_lock);
164 }
165
166 return ret;
167}
168EXPORT_SYMBOL_GPL(wm831x_reg_unlock);
169
170static int wm831x_read(struct wm831x *wm831x, unsigned short reg,
171 int bytes, void *dest)
172{
173 int ret, i;
174 u16 *buf = dest;
175
176 BUG_ON(bytes % 2);
177 BUG_ON(bytes <= 0);
178
179 ret = wm831x->read_dev(wm831x, reg, bytes, dest);
180 if (ret < 0)
181 return ret;
182
183 for (i = 0; i < bytes / 2; i++) {
184 buf[i] = be16_to_cpu(buf[i]);
185
186 dev_vdbg(wm831x->dev, "Read %04x from R%d(0x%x)\n",
187 buf[i], reg + i, reg + i);
188 }
189
190 return 0;
191}
192
193/**
194 * wm831x_reg_read: Read a single WM831x register.
195 *
196 * @wm831x: Device to read from.
197 * @reg: Register to read.
198 */
199int wm831x_reg_read(struct wm831x *wm831x, unsigned short reg)
200{
201 unsigned short val;
202 int ret;
203
204 mutex_lock(&wm831x->io_lock);
205
206 ret = wm831x_read(wm831x, reg, 2, &val);
207
208 mutex_unlock(&wm831x->io_lock);
209
210 if (ret < 0)
211 return ret;
212 else
213 return val;
214}
215EXPORT_SYMBOL_GPL(wm831x_reg_read);
216
217/**
218 * wm831x_bulk_read: Read multiple WM831x registers
219 *
220 * @wm831x: Device to read from
221 * @reg: First register
222 * @count: Number of registers
223 * @buf: Buffer to fill.
224 */
225int wm831x_bulk_read(struct wm831x *wm831x, unsigned short reg,
226 int count, u16 *buf)
227{
228 int ret;
229
230 mutex_lock(&wm831x->io_lock);
231
232 ret = wm831x_read(wm831x, reg, count * 2, buf);
233
234 mutex_unlock(&wm831x->io_lock);
235
236 return ret;
237}
238EXPORT_SYMBOL_GPL(wm831x_bulk_read);
239
240static int wm831x_write(struct wm831x *wm831x, unsigned short reg,
241 int bytes, void *src)
242{
243 u16 *buf = src;
244 int i;
245
246 BUG_ON(bytes % 2);
247 BUG_ON(bytes <= 0);
248
249 for (i = 0; i < bytes / 2; i++) {
250 if (wm831x_reg_locked(wm831x, reg))
251 return -EPERM;
252
253 dev_vdbg(wm831x->dev, "Write %04x to R%d(0x%x)\n",
254 buf[i], reg + i, reg + i);
255
256 buf[i] = cpu_to_be16(buf[i]);
257 }
258
259 return wm831x->write_dev(wm831x, reg, bytes, src);
260}
261
262/**
263 * wm831x_reg_write: Write a single WM831x register.
264 *
265 * @wm831x: Device to write to.
266 * @reg: Register to write to.
267 * @val: Value to write.
268 */
269int wm831x_reg_write(struct wm831x *wm831x, unsigned short reg,
270 unsigned short val)
271{
272 int ret;
273
274 mutex_lock(&wm831x->io_lock);
275
276 ret = wm831x_write(wm831x, reg, 2, &val);
277
278 mutex_unlock(&wm831x->io_lock);
279
280 return ret;
281}
282EXPORT_SYMBOL_GPL(wm831x_reg_write);
283
284/**
285 * wm831x_set_bits: Set the value of a bitfield in a WM831x register
286 *
287 * @wm831x: Device to write to.
288 * @reg: Register to write to.
289 * @mask: Mask of bits to set.
290 * @val: Value to set (unshifted)
291 */
292int wm831x_set_bits(struct wm831x *wm831x, unsigned short reg,
293 unsigned short mask, unsigned short val)
294{
295 int ret;
296 u16 r;
297
298 mutex_lock(&wm831x->io_lock);
299
300 ret = wm831x_read(wm831x, reg, 2, &r);
301 if (ret < 0)
302 goto out;
303
304 r &= ~mask;
305 r |= val;
306
307 ret = wm831x_write(wm831x, reg, 2, &r);
308
309out:
310 mutex_unlock(&wm831x->io_lock);
311
312 return ret;
313}
314EXPORT_SYMBOL_GPL(wm831x_set_bits);
315
Mark Brown7e9f9fd2009-07-27 14:45:54 +0100316/**
317 * wm831x_auxadc_read: Read a value from the WM831x AUXADC
318 *
319 * @wm831x: Device to read from.
320 * @input: AUXADC input to read.
321 */
322int wm831x_auxadc_read(struct wm831x *wm831x, enum wm831x_auxadc input)
323{
324 int tries = 10;
325 int ret, src;
326
327 mutex_lock(&wm831x->auxadc_lock);
328
329 ret = wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL,
330 WM831X_AUX_ENA, WM831X_AUX_ENA);
331 if (ret < 0) {
332 dev_err(wm831x->dev, "Failed to enable AUXADC: %d\n", ret);
333 goto out;
334 }
335
336 /* We force a single source at present */
337 src = input;
338 ret = wm831x_reg_write(wm831x, WM831X_AUXADC_SOURCE,
339 1 << src);
340 if (ret < 0) {
341 dev_err(wm831x->dev, "Failed to set AUXADC source: %d\n", ret);
342 goto out;
343 }
344
345 ret = wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL,
346 WM831X_AUX_CVT_ENA, WM831X_AUX_CVT_ENA);
347 if (ret < 0) {
348 dev_err(wm831x->dev, "Failed to start AUXADC: %d\n", ret);
349 goto disable;
350 }
351
352 do {
353 msleep(1);
354
355 ret = wm831x_reg_read(wm831x, WM831X_AUXADC_CONTROL);
356 if (ret < 0)
357 ret = WM831X_AUX_CVT_ENA;
358 } while ((ret & WM831X_AUX_CVT_ENA) && --tries);
359
360 if (ret & WM831X_AUX_CVT_ENA) {
361 dev_err(wm831x->dev, "Timed out reading AUXADC\n");
362 ret = -EBUSY;
363 goto disable;
364 }
365
366 ret = wm831x_reg_read(wm831x, WM831X_AUXADC_DATA);
367 if (ret < 0) {
368 dev_err(wm831x->dev, "Failed to read AUXADC data: %d\n", ret);
369 } else {
370 src = ((ret & WM831X_AUX_DATA_SRC_MASK)
371 >> WM831X_AUX_DATA_SRC_SHIFT) - 1;
372
373 if (src == 14)
374 src = WM831X_AUX_CAL;
375
376 if (src != input) {
377 dev_err(wm831x->dev, "Data from source %d not %d\n",
378 src, input);
379 ret = -EINVAL;
380 } else {
381 ret &= WM831X_AUX_DATA_MASK;
382 }
383 }
384
385disable:
386 wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL, WM831X_AUX_ENA, 0);
387out:
388 mutex_unlock(&wm831x->auxadc_lock);
389 return ret;
390}
391EXPORT_SYMBOL_GPL(wm831x_auxadc_read);
392
393/**
394 * wm831x_auxadc_read_uv: Read a voltage from the WM831x AUXADC
395 *
396 * @wm831x: Device to read from.
397 * @input: AUXADC input to read.
398 */
399int wm831x_auxadc_read_uv(struct wm831x *wm831x, enum wm831x_auxadc input)
400{
401 int ret;
402
403 ret = wm831x_auxadc_read(wm831x, input);
404 if (ret < 0)
405 return ret;
406
407 ret *= 1465;
408
409 return ret;
410}
411EXPORT_SYMBOL_GPL(wm831x_auxadc_read_uv);
412
Mark Brownd2bedfe2009-07-27 14:45:52 +0100413static struct resource wm831x_dcdc1_resources[] = {
414 {
415 .start = WM831X_DC1_CONTROL_1,
416 .end = WM831X_DC1_DVS_CONTROL,
417 .flags = IORESOURCE_IO,
418 },
419 {
420 .name = "UV",
421 .start = WM831X_IRQ_UV_DC1,
422 .end = WM831X_IRQ_UV_DC1,
423 .flags = IORESOURCE_IRQ,
424 },
425 {
426 .name = "HC",
427 .start = WM831X_IRQ_HC_DC1,
428 .end = WM831X_IRQ_HC_DC1,
429 .flags = IORESOURCE_IRQ,
430 },
431};
432
433
434static struct resource wm831x_dcdc2_resources[] = {
435 {
436 .start = WM831X_DC2_CONTROL_1,
437 .end = WM831X_DC2_DVS_CONTROL,
438 .flags = IORESOURCE_IO,
439 },
440 {
441 .name = "UV",
442 .start = WM831X_IRQ_UV_DC2,
443 .end = WM831X_IRQ_UV_DC2,
444 .flags = IORESOURCE_IRQ,
445 },
446 {
447 .name = "HC",
448 .start = WM831X_IRQ_HC_DC2,
449 .end = WM831X_IRQ_HC_DC2,
450 .flags = IORESOURCE_IRQ,
451 },
452};
453
454static struct resource wm831x_dcdc3_resources[] = {
455 {
456 .start = WM831X_DC3_CONTROL_1,
457 .end = WM831X_DC3_SLEEP_CONTROL,
458 .flags = IORESOURCE_IO,
459 },
460 {
461 .name = "UV",
462 .start = WM831X_IRQ_UV_DC3,
463 .end = WM831X_IRQ_UV_DC3,
464 .flags = IORESOURCE_IRQ,
465 },
466};
467
468static struct resource wm831x_dcdc4_resources[] = {
469 {
470 .start = WM831X_DC4_CONTROL,
471 .end = WM831X_DC4_SLEEP_CONTROL,
472 .flags = IORESOURCE_IO,
473 },
474 {
475 .name = "UV",
476 .start = WM831X_IRQ_UV_DC4,
477 .end = WM831X_IRQ_UV_DC4,
478 .flags = IORESOURCE_IRQ,
479 },
480};
481
Mark Brownd4e0a892009-10-01 15:41:07 +0100482static struct resource wm8320_dcdc4_buck_resources[] = {
483 {
484 .start = WM831X_DC4_CONTROL,
485 .end = WM832X_DC4_SLEEP_CONTROL,
486 .flags = IORESOURCE_IO,
487 },
488 {
489 .name = "UV",
490 .start = WM831X_IRQ_UV_DC4,
491 .end = WM831X_IRQ_UV_DC4,
492 .flags = IORESOURCE_IRQ,
493 },
494};
495
Mark Brownd2bedfe2009-07-27 14:45:52 +0100496static struct resource wm831x_gpio_resources[] = {
497 {
498 .start = WM831X_IRQ_GPIO_1,
499 .end = WM831X_IRQ_GPIO_16,
500 .flags = IORESOURCE_IRQ,
501 },
502};
503
504static struct resource wm831x_isink1_resources[] = {
505 {
506 .start = WM831X_CURRENT_SINK_1,
507 .end = WM831X_CURRENT_SINK_1,
508 .flags = IORESOURCE_IO,
509 },
510 {
511 .start = WM831X_IRQ_CS1,
512 .end = WM831X_IRQ_CS1,
513 .flags = IORESOURCE_IRQ,
514 },
515};
516
517static struct resource wm831x_isink2_resources[] = {
518 {
519 .start = WM831X_CURRENT_SINK_2,
520 .end = WM831X_CURRENT_SINK_2,
521 .flags = IORESOURCE_IO,
522 },
523 {
524 .start = WM831X_IRQ_CS2,
525 .end = WM831X_IRQ_CS2,
526 .flags = IORESOURCE_IRQ,
527 },
528};
529
530static struct resource wm831x_ldo1_resources[] = {
531 {
532 .start = WM831X_LDO1_CONTROL,
533 .end = WM831X_LDO1_SLEEP_CONTROL,
534 .flags = IORESOURCE_IO,
535 },
536 {
537 .name = "UV",
538 .start = WM831X_IRQ_UV_LDO1,
539 .end = WM831X_IRQ_UV_LDO1,
540 .flags = IORESOURCE_IRQ,
541 },
542};
543
544static struct resource wm831x_ldo2_resources[] = {
545 {
546 .start = WM831X_LDO2_CONTROL,
547 .end = WM831X_LDO2_SLEEP_CONTROL,
548 .flags = IORESOURCE_IO,
549 },
550 {
551 .name = "UV",
552 .start = WM831X_IRQ_UV_LDO2,
553 .end = WM831X_IRQ_UV_LDO2,
554 .flags = IORESOURCE_IRQ,
555 },
556};
557
558static struct resource wm831x_ldo3_resources[] = {
559 {
560 .start = WM831X_LDO3_CONTROL,
561 .end = WM831X_LDO3_SLEEP_CONTROL,
562 .flags = IORESOURCE_IO,
563 },
564 {
565 .name = "UV",
566 .start = WM831X_IRQ_UV_LDO3,
567 .end = WM831X_IRQ_UV_LDO3,
568 .flags = IORESOURCE_IRQ,
569 },
570};
571
572static struct resource wm831x_ldo4_resources[] = {
573 {
574 .start = WM831X_LDO4_CONTROL,
575 .end = WM831X_LDO4_SLEEP_CONTROL,
576 .flags = IORESOURCE_IO,
577 },
578 {
579 .name = "UV",
580 .start = WM831X_IRQ_UV_LDO4,
581 .end = WM831X_IRQ_UV_LDO4,
582 .flags = IORESOURCE_IRQ,
583 },
584};
585
586static struct resource wm831x_ldo5_resources[] = {
587 {
588 .start = WM831X_LDO5_CONTROL,
589 .end = WM831X_LDO5_SLEEP_CONTROL,
590 .flags = IORESOURCE_IO,
591 },
592 {
593 .name = "UV",
594 .start = WM831X_IRQ_UV_LDO5,
595 .end = WM831X_IRQ_UV_LDO5,
596 .flags = IORESOURCE_IRQ,
597 },
598};
599
600static struct resource wm831x_ldo6_resources[] = {
601 {
602 .start = WM831X_LDO6_CONTROL,
603 .end = WM831X_LDO6_SLEEP_CONTROL,
604 .flags = IORESOURCE_IO,
605 },
606 {
607 .name = "UV",
608 .start = WM831X_IRQ_UV_LDO6,
609 .end = WM831X_IRQ_UV_LDO6,
610 .flags = IORESOURCE_IRQ,
611 },
612};
613
614static struct resource wm831x_ldo7_resources[] = {
615 {
616 .start = WM831X_LDO7_CONTROL,
617 .end = WM831X_LDO7_SLEEP_CONTROL,
618 .flags = IORESOURCE_IO,
619 },
620 {
621 .name = "UV",
622 .start = WM831X_IRQ_UV_LDO7,
623 .end = WM831X_IRQ_UV_LDO7,
624 .flags = IORESOURCE_IRQ,
625 },
626};
627
628static struct resource wm831x_ldo8_resources[] = {
629 {
630 .start = WM831X_LDO8_CONTROL,
631 .end = WM831X_LDO8_SLEEP_CONTROL,
632 .flags = IORESOURCE_IO,
633 },
634 {
635 .name = "UV",
636 .start = WM831X_IRQ_UV_LDO8,
637 .end = WM831X_IRQ_UV_LDO8,
638 .flags = IORESOURCE_IRQ,
639 },
640};
641
642static struct resource wm831x_ldo9_resources[] = {
643 {
644 .start = WM831X_LDO9_CONTROL,
645 .end = WM831X_LDO9_SLEEP_CONTROL,
646 .flags = IORESOURCE_IO,
647 },
648 {
649 .name = "UV",
650 .start = WM831X_IRQ_UV_LDO9,
651 .end = WM831X_IRQ_UV_LDO9,
652 .flags = IORESOURCE_IRQ,
653 },
654};
655
656static struct resource wm831x_ldo10_resources[] = {
657 {
658 .start = WM831X_LDO10_CONTROL,
659 .end = WM831X_LDO10_SLEEP_CONTROL,
660 .flags = IORESOURCE_IO,
661 },
662 {
663 .name = "UV",
664 .start = WM831X_IRQ_UV_LDO10,
665 .end = WM831X_IRQ_UV_LDO10,
666 .flags = IORESOURCE_IRQ,
667 },
668};
669
670static struct resource wm831x_ldo11_resources[] = {
671 {
672 .start = WM831X_LDO11_ON_CONTROL,
673 .end = WM831X_LDO11_SLEEP_CONTROL,
674 .flags = IORESOURCE_IO,
675 },
676};
677
678static struct resource wm831x_on_resources[] = {
679 {
680 .start = WM831X_IRQ_ON,
681 .end = WM831X_IRQ_ON,
682 .flags = IORESOURCE_IRQ,
683 },
684};
685
686
687static struct resource wm831x_power_resources[] = {
688 {
689 .name = "SYSLO",
690 .start = WM831X_IRQ_PPM_SYSLO,
691 .end = WM831X_IRQ_PPM_SYSLO,
692 .flags = IORESOURCE_IRQ,
693 },
694 {
695 .name = "PWR SRC",
696 .start = WM831X_IRQ_PPM_PWR_SRC,
697 .end = WM831X_IRQ_PPM_PWR_SRC,
698 .flags = IORESOURCE_IRQ,
699 },
700 {
701 .name = "USB CURR",
702 .start = WM831X_IRQ_PPM_USB_CURR,
703 .end = WM831X_IRQ_PPM_USB_CURR,
704 .flags = IORESOURCE_IRQ,
705 },
706 {
707 .name = "BATT HOT",
708 .start = WM831X_IRQ_CHG_BATT_HOT,
709 .end = WM831X_IRQ_CHG_BATT_HOT,
710 .flags = IORESOURCE_IRQ,
711 },
712 {
713 .name = "BATT COLD",
714 .start = WM831X_IRQ_CHG_BATT_COLD,
715 .end = WM831X_IRQ_CHG_BATT_COLD,
716 .flags = IORESOURCE_IRQ,
717 },
718 {
719 .name = "BATT FAIL",
720 .start = WM831X_IRQ_CHG_BATT_FAIL,
721 .end = WM831X_IRQ_CHG_BATT_FAIL,
722 .flags = IORESOURCE_IRQ,
723 },
724 {
725 .name = "OV",
726 .start = WM831X_IRQ_CHG_OV,
727 .end = WM831X_IRQ_CHG_OV,
728 .flags = IORESOURCE_IRQ,
729 },
730 {
731 .name = "END",
732 .start = WM831X_IRQ_CHG_END,
733 .end = WM831X_IRQ_CHG_END,
734 .flags = IORESOURCE_IRQ,
735 },
736 {
737 .name = "TO",
738 .start = WM831X_IRQ_CHG_TO,
739 .end = WM831X_IRQ_CHG_TO,
740 .flags = IORESOURCE_IRQ,
741 },
742 {
743 .name = "MODE",
744 .start = WM831X_IRQ_CHG_MODE,
745 .end = WM831X_IRQ_CHG_MODE,
746 .flags = IORESOURCE_IRQ,
747 },
748 {
749 .name = "START",
750 .start = WM831X_IRQ_CHG_START,
751 .end = WM831X_IRQ_CHG_START,
752 .flags = IORESOURCE_IRQ,
753 },
754};
755
756static struct resource wm831x_rtc_resources[] = {
757 {
758 .name = "PER",
759 .start = WM831X_IRQ_RTC_PER,
760 .end = WM831X_IRQ_RTC_PER,
761 .flags = IORESOURCE_IRQ,
762 },
763 {
764 .name = "ALM",
765 .start = WM831X_IRQ_RTC_ALM,
766 .end = WM831X_IRQ_RTC_ALM,
767 .flags = IORESOURCE_IRQ,
768 },
769};
770
771static struct resource wm831x_status1_resources[] = {
772 {
773 .start = WM831X_STATUS_LED_1,
774 .end = WM831X_STATUS_LED_1,
775 .flags = IORESOURCE_IO,
776 },
777};
778
779static struct resource wm831x_status2_resources[] = {
780 {
781 .start = WM831X_STATUS_LED_2,
782 .end = WM831X_STATUS_LED_2,
783 .flags = IORESOURCE_IO,
784 },
785};
786
787static struct resource wm831x_touch_resources[] = {
788 {
789 .name = "TCHPD",
790 .start = WM831X_IRQ_TCHPD,
791 .end = WM831X_IRQ_TCHPD,
792 .flags = IORESOURCE_IRQ,
793 },
794 {
795 .name = "TCHDATA",
796 .start = WM831X_IRQ_TCHDATA,
797 .end = WM831X_IRQ_TCHDATA,
798 .flags = IORESOURCE_IRQ,
799 },
800};
801
802static struct resource wm831x_wdt_resources[] = {
803 {
804 .start = WM831X_IRQ_WDOG_TO,
805 .end = WM831X_IRQ_WDOG_TO,
806 .flags = IORESOURCE_IRQ,
807 },
808};
809
810static struct mfd_cell wm8310_devs[] = {
811 {
Mark Brownc26964e2009-10-01 15:41:06 +0100812 .name = "wm831x-backup",
813 },
814 {
Mark Brownd2bedfe2009-07-27 14:45:52 +0100815 .name = "wm831x-buckv",
816 .id = 1,
817 .num_resources = ARRAY_SIZE(wm831x_dcdc1_resources),
818 .resources = wm831x_dcdc1_resources,
819 },
820 {
821 .name = "wm831x-buckv",
822 .id = 2,
823 .num_resources = ARRAY_SIZE(wm831x_dcdc2_resources),
824 .resources = wm831x_dcdc2_resources,
825 },
826 {
827 .name = "wm831x-buckp",
828 .id = 3,
829 .num_resources = ARRAY_SIZE(wm831x_dcdc3_resources),
830 .resources = wm831x_dcdc3_resources,
831 },
832 {
833 .name = "wm831x-boostp",
834 .id = 4,
835 .num_resources = ARRAY_SIZE(wm831x_dcdc4_resources),
836 .resources = wm831x_dcdc4_resources,
837 },
838 {
839 .name = "wm831x-epe",
840 .id = 1,
841 },
842 {
843 .name = "wm831x-epe",
844 .id = 2,
845 },
846 {
847 .name = "wm831x-gpio",
848 .num_resources = ARRAY_SIZE(wm831x_gpio_resources),
849 .resources = wm831x_gpio_resources,
850 },
851 {
852 .name = "wm831x-hwmon",
853 },
854 {
855 .name = "wm831x-isink",
856 .id = 1,
857 .num_resources = ARRAY_SIZE(wm831x_isink1_resources),
858 .resources = wm831x_isink1_resources,
859 },
860 {
861 .name = "wm831x-isink",
862 .id = 2,
863 .num_resources = ARRAY_SIZE(wm831x_isink2_resources),
864 .resources = wm831x_isink2_resources,
865 },
866 {
867 .name = "wm831x-ldo",
868 .id = 1,
869 .num_resources = ARRAY_SIZE(wm831x_ldo1_resources),
870 .resources = wm831x_ldo1_resources,
871 },
872 {
873 .name = "wm831x-ldo",
874 .id = 2,
875 .num_resources = ARRAY_SIZE(wm831x_ldo2_resources),
876 .resources = wm831x_ldo2_resources,
877 },
878 {
879 .name = "wm831x-ldo",
880 .id = 3,
881 .num_resources = ARRAY_SIZE(wm831x_ldo3_resources),
882 .resources = wm831x_ldo3_resources,
883 },
884 {
885 .name = "wm831x-ldo",
886 .id = 4,
887 .num_resources = ARRAY_SIZE(wm831x_ldo4_resources),
888 .resources = wm831x_ldo4_resources,
889 },
890 {
891 .name = "wm831x-ldo",
892 .id = 5,
893 .num_resources = ARRAY_SIZE(wm831x_ldo5_resources),
894 .resources = wm831x_ldo5_resources,
895 },
896 {
897 .name = "wm831x-ldo",
898 .id = 6,
899 .num_resources = ARRAY_SIZE(wm831x_ldo6_resources),
900 .resources = wm831x_ldo6_resources,
901 },
902 {
903 .name = "wm831x-aldo",
904 .id = 7,
905 .num_resources = ARRAY_SIZE(wm831x_ldo7_resources),
906 .resources = wm831x_ldo7_resources,
907 },
908 {
909 .name = "wm831x-aldo",
910 .id = 8,
911 .num_resources = ARRAY_SIZE(wm831x_ldo8_resources),
912 .resources = wm831x_ldo8_resources,
913 },
914 {
915 .name = "wm831x-aldo",
916 .id = 9,
917 .num_resources = ARRAY_SIZE(wm831x_ldo9_resources),
918 .resources = wm831x_ldo9_resources,
919 },
920 {
921 .name = "wm831x-aldo",
922 .id = 10,
923 .num_resources = ARRAY_SIZE(wm831x_ldo10_resources),
924 .resources = wm831x_ldo10_resources,
925 },
926 {
927 .name = "wm831x-alive-ldo",
928 .id = 11,
929 .num_resources = ARRAY_SIZE(wm831x_ldo11_resources),
930 .resources = wm831x_ldo11_resources,
931 },
932 {
933 .name = "wm831x-on",
934 .num_resources = ARRAY_SIZE(wm831x_on_resources),
935 .resources = wm831x_on_resources,
936 },
937 {
938 .name = "wm831x-power",
939 .num_resources = ARRAY_SIZE(wm831x_power_resources),
940 .resources = wm831x_power_resources,
941 },
942 {
943 .name = "wm831x-rtc",
944 .num_resources = ARRAY_SIZE(wm831x_rtc_resources),
945 .resources = wm831x_rtc_resources,
946 },
947 {
948 .name = "wm831x-status",
949 .id = 1,
950 .num_resources = ARRAY_SIZE(wm831x_status1_resources),
951 .resources = wm831x_status1_resources,
952 },
953 {
954 .name = "wm831x-status",
955 .id = 2,
956 .num_resources = ARRAY_SIZE(wm831x_status2_resources),
957 .resources = wm831x_status2_resources,
958 },
959 {
960 .name = "wm831x-watchdog",
961 .num_resources = ARRAY_SIZE(wm831x_wdt_resources),
962 .resources = wm831x_wdt_resources,
963 },
964};
965
966static struct mfd_cell wm8311_devs[] = {
967 {
Mark Brownc26964e2009-10-01 15:41:06 +0100968 .name = "wm831x-backup",
969 },
970 {
Mark Brownd2bedfe2009-07-27 14:45:52 +0100971 .name = "wm831x-buckv",
972 .id = 1,
973 .num_resources = ARRAY_SIZE(wm831x_dcdc1_resources),
974 .resources = wm831x_dcdc1_resources,
975 },
976 {
977 .name = "wm831x-buckv",
978 .id = 2,
979 .num_resources = ARRAY_SIZE(wm831x_dcdc2_resources),
980 .resources = wm831x_dcdc2_resources,
981 },
982 {
983 .name = "wm831x-buckp",
984 .id = 3,
985 .num_resources = ARRAY_SIZE(wm831x_dcdc3_resources),
986 .resources = wm831x_dcdc3_resources,
987 },
988 {
989 .name = "wm831x-boostp",
990 .id = 4,
991 .num_resources = ARRAY_SIZE(wm831x_dcdc4_resources),
992 .resources = wm831x_dcdc4_resources,
993 },
994 {
995 .name = "wm831x-epe",
996 .id = 1,
997 },
998 {
999 .name = "wm831x-epe",
1000 .id = 2,
1001 },
1002 {
1003 .name = "wm831x-gpio",
1004 .num_resources = ARRAY_SIZE(wm831x_gpio_resources),
1005 .resources = wm831x_gpio_resources,
1006 },
1007 {
1008 .name = "wm831x-hwmon",
1009 },
1010 {
1011 .name = "wm831x-isink",
1012 .id = 1,
1013 .num_resources = ARRAY_SIZE(wm831x_isink1_resources),
1014 .resources = wm831x_isink1_resources,
1015 },
1016 {
1017 .name = "wm831x-isink",
1018 .id = 2,
1019 .num_resources = ARRAY_SIZE(wm831x_isink2_resources),
1020 .resources = wm831x_isink2_resources,
1021 },
1022 {
1023 .name = "wm831x-ldo",
1024 .id = 1,
1025 .num_resources = ARRAY_SIZE(wm831x_ldo1_resources),
1026 .resources = wm831x_ldo1_resources,
1027 },
1028 {
1029 .name = "wm831x-ldo",
1030 .id = 2,
1031 .num_resources = ARRAY_SIZE(wm831x_ldo2_resources),
1032 .resources = wm831x_ldo2_resources,
1033 },
1034 {
1035 .name = "wm831x-ldo",
1036 .id = 3,
1037 .num_resources = ARRAY_SIZE(wm831x_ldo3_resources),
1038 .resources = wm831x_ldo3_resources,
1039 },
1040 {
1041 .name = "wm831x-ldo",
1042 .id = 4,
1043 .num_resources = ARRAY_SIZE(wm831x_ldo4_resources),
1044 .resources = wm831x_ldo4_resources,
1045 },
1046 {
1047 .name = "wm831x-ldo",
1048 .id = 5,
1049 .num_resources = ARRAY_SIZE(wm831x_ldo5_resources),
1050 .resources = wm831x_ldo5_resources,
1051 },
1052 {
1053 .name = "wm831x-aldo",
1054 .id = 7,
1055 .num_resources = ARRAY_SIZE(wm831x_ldo7_resources),
1056 .resources = wm831x_ldo7_resources,
1057 },
1058 {
1059 .name = "wm831x-alive-ldo",
1060 .id = 11,
1061 .num_resources = ARRAY_SIZE(wm831x_ldo11_resources),
1062 .resources = wm831x_ldo11_resources,
1063 },
1064 {
1065 .name = "wm831x-on",
1066 .num_resources = ARRAY_SIZE(wm831x_on_resources),
1067 .resources = wm831x_on_resources,
1068 },
1069 {
1070 .name = "wm831x-power",
1071 .num_resources = ARRAY_SIZE(wm831x_power_resources),
1072 .resources = wm831x_power_resources,
1073 },
1074 {
1075 .name = "wm831x-rtc",
1076 .num_resources = ARRAY_SIZE(wm831x_rtc_resources),
1077 .resources = wm831x_rtc_resources,
1078 },
1079 {
1080 .name = "wm831x-status",
1081 .id = 1,
1082 .num_resources = ARRAY_SIZE(wm831x_status1_resources),
1083 .resources = wm831x_status1_resources,
1084 },
1085 {
1086 .name = "wm831x-status",
1087 .id = 2,
1088 .num_resources = ARRAY_SIZE(wm831x_status2_resources),
1089 .resources = wm831x_status2_resources,
1090 },
1091 {
1092 .name = "wm831x-touch",
1093 .num_resources = ARRAY_SIZE(wm831x_touch_resources),
1094 .resources = wm831x_touch_resources,
1095 },
1096 {
1097 .name = "wm831x-watchdog",
1098 .num_resources = ARRAY_SIZE(wm831x_wdt_resources),
1099 .resources = wm831x_wdt_resources,
1100 },
1101};
1102
1103static struct mfd_cell wm8312_devs[] = {
1104 {
Mark Brownc26964e2009-10-01 15:41:06 +01001105 .name = "wm831x-backup",
1106 },
1107 {
Mark Brownd2bedfe2009-07-27 14:45:52 +01001108 .name = "wm831x-buckv",
1109 .id = 1,
1110 .num_resources = ARRAY_SIZE(wm831x_dcdc1_resources),
1111 .resources = wm831x_dcdc1_resources,
1112 },
1113 {
1114 .name = "wm831x-buckv",
1115 .id = 2,
1116 .num_resources = ARRAY_SIZE(wm831x_dcdc2_resources),
1117 .resources = wm831x_dcdc2_resources,
1118 },
1119 {
1120 .name = "wm831x-buckp",
1121 .id = 3,
1122 .num_resources = ARRAY_SIZE(wm831x_dcdc3_resources),
1123 .resources = wm831x_dcdc3_resources,
1124 },
1125 {
1126 .name = "wm831x-boostp",
1127 .id = 4,
1128 .num_resources = ARRAY_SIZE(wm831x_dcdc4_resources),
1129 .resources = wm831x_dcdc4_resources,
1130 },
1131 {
1132 .name = "wm831x-epe",
1133 .id = 1,
1134 },
1135 {
1136 .name = "wm831x-epe",
1137 .id = 2,
1138 },
1139 {
1140 .name = "wm831x-gpio",
1141 .num_resources = ARRAY_SIZE(wm831x_gpio_resources),
1142 .resources = wm831x_gpio_resources,
1143 },
1144 {
1145 .name = "wm831x-hwmon",
1146 },
1147 {
1148 .name = "wm831x-isink",
1149 .id = 1,
1150 .num_resources = ARRAY_SIZE(wm831x_isink1_resources),
1151 .resources = wm831x_isink1_resources,
1152 },
1153 {
1154 .name = "wm831x-isink",
1155 .id = 2,
1156 .num_resources = ARRAY_SIZE(wm831x_isink2_resources),
1157 .resources = wm831x_isink2_resources,
1158 },
1159 {
1160 .name = "wm831x-ldo",
1161 .id = 1,
1162 .num_resources = ARRAY_SIZE(wm831x_ldo1_resources),
1163 .resources = wm831x_ldo1_resources,
1164 },
1165 {
1166 .name = "wm831x-ldo",
1167 .id = 2,
1168 .num_resources = ARRAY_SIZE(wm831x_ldo2_resources),
1169 .resources = wm831x_ldo2_resources,
1170 },
1171 {
1172 .name = "wm831x-ldo",
1173 .id = 3,
1174 .num_resources = ARRAY_SIZE(wm831x_ldo3_resources),
1175 .resources = wm831x_ldo3_resources,
1176 },
1177 {
1178 .name = "wm831x-ldo",
1179 .id = 4,
1180 .num_resources = ARRAY_SIZE(wm831x_ldo4_resources),
1181 .resources = wm831x_ldo4_resources,
1182 },
1183 {
1184 .name = "wm831x-ldo",
1185 .id = 5,
1186 .num_resources = ARRAY_SIZE(wm831x_ldo5_resources),
1187 .resources = wm831x_ldo5_resources,
1188 },
1189 {
1190 .name = "wm831x-ldo",
1191 .id = 6,
1192 .num_resources = ARRAY_SIZE(wm831x_ldo6_resources),
1193 .resources = wm831x_ldo6_resources,
1194 },
1195 {
1196 .name = "wm831x-aldo",
1197 .id = 7,
1198 .num_resources = ARRAY_SIZE(wm831x_ldo7_resources),
1199 .resources = wm831x_ldo7_resources,
1200 },
1201 {
1202 .name = "wm831x-aldo",
1203 .id = 8,
1204 .num_resources = ARRAY_SIZE(wm831x_ldo8_resources),
1205 .resources = wm831x_ldo8_resources,
1206 },
1207 {
1208 .name = "wm831x-aldo",
1209 .id = 9,
1210 .num_resources = ARRAY_SIZE(wm831x_ldo9_resources),
1211 .resources = wm831x_ldo9_resources,
1212 },
1213 {
1214 .name = "wm831x-aldo",
1215 .id = 10,
1216 .num_resources = ARRAY_SIZE(wm831x_ldo10_resources),
1217 .resources = wm831x_ldo10_resources,
1218 },
1219 {
1220 .name = "wm831x-alive-ldo",
1221 .id = 11,
1222 .num_resources = ARRAY_SIZE(wm831x_ldo11_resources),
1223 .resources = wm831x_ldo11_resources,
1224 },
1225 {
1226 .name = "wm831x-on",
1227 .num_resources = ARRAY_SIZE(wm831x_on_resources),
1228 .resources = wm831x_on_resources,
1229 },
1230 {
1231 .name = "wm831x-power",
1232 .num_resources = ARRAY_SIZE(wm831x_power_resources),
1233 .resources = wm831x_power_resources,
1234 },
1235 {
1236 .name = "wm831x-rtc",
1237 .num_resources = ARRAY_SIZE(wm831x_rtc_resources),
1238 .resources = wm831x_rtc_resources,
1239 },
1240 {
1241 .name = "wm831x-status",
1242 .id = 1,
1243 .num_resources = ARRAY_SIZE(wm831x_status1_resources),
1244 .resources = wm831x_status1_resources,
1245 },
1246 {
1247 .name = "wm831x-status",
1248 .id = 2,
1249 .num_resources = ARRAY_SIZE(wm831x_status2_resources),
1250 .resources = wm831x_status2_resources,
1251 },
1252 {
1253 .name = "wm831x-touch",
1254 .num_resources = ARRAY_SIZE(wm831x_touch_resources),
1255 .resources = wm831x_touch_resources,
1256 },
1257 {
1258 .name = "wm831x-watchdog",
1259 .num_resources = ARRAY_SIZE(wm831x_wdt_resources),
1260 .resources = wm831x_wdt_resources,
1261 },
1262};
1263
Mark Brownd4e0a892009-10-01 15:41:07 +01001264static struct mfd_cell wm8320_devs[] = {
1265 {
1266 .name = "wm831x-backup",
1267 },
1268 {
1269 .name = "wm831x-buckv",
1270 .id = 1,
1271 .num_resources = ARRAY_SIZE(wm831x_dcdc1_resources),
1272 .resources = wm831x_dcdc1_resources,
1273 },
1274 {
1275 .name = "wm831x-buckv",
1276 .id = 2,
1277 .num_resources = ARRAY_SIZE(wm831x_dcdc2_resources),
1278 .resources = wm831x_dcdc2_resources,
1279 },
1280 {
1281 .name = "wm831x-buckp",
1282 .id = 3,
1283 .num_resources = ARRAY_SIZE(wm831x_dcdc3_resources),
1284 .resources = wm831x_dcdc3_resources,
1285 },
1286 {
1287 .name = "wm831x-buckp",
1288 .id = 4,
1289 .num_resources = ARRAY_SIZE(wm8320_dcdc4_buck_resources),
1290 .resources = wm8320_dcdc4_buck_resources,
1291 },
1292 {
1293 .name = "wm831x-gpio",
1294 .num_resources = ARRAY_SIZE(wm831x_gpio_resources),
1295 .resources = wm831x_gpio_resources,
1296 },
1297 {
1298 .name = "wm831x-hwmon",
1299 },
1300 {
1301 .name = "wm831x-ldo",
1302 .id = 1,
1303 .num_resources = ARRAY_SIZE(wm831x_ldo1_resources),
1304 .resources = wm831x_ldo1_resources,
1305 },
1306 {
1307 .name = "wm831x-ldo",
1308 .id = 2,
1309 .num_resources = ARRAY_SIZE(wm831x_ldo2_resources),
1310 .resources = wm831x_ldo2_resources,
1311 },
1312 {
1313 .name = "wm831x-ldo",
1314 .id = 3,
1315 .num_resources = ARRAY_SIZE(wm831x_ldo3_resources),
1316 .resources = wm831x_ldo3_resources,
1317 },
1318 {
1319 .name = "wm831x-ldo",
1320 .id = 4,
1321 .num_resources = ARRAY_SIZE(wm831x_ldo4_resources),
1322 .resources = wm831x_ldo4_resources,
1323 },
1324 {
1325 .name = "wm831x-ldo",
1326 .id = 5,
1327 .num_resources = ARRAY_SIZE(wm831x_ldo5_resources),
1328 .resources = wm831x_ldo5_resources,
1329 },
1330 {
1331 .name = "wm831x-ldo",
1332 .id = 6,
1333 .num_resources = ARRAY_SIZE(wm831x_ldo6_resources),
1334 .resources = wm831x_ldo6_resources,
1335 },
1336 {
1337 .name = "wm831x-aldo",
1338 .id = 7,
1339 .num_resources = ARRAY_SIZE(wm831x_ldo7_resources),
1340 .resources = wm831x_ldo7_resources,
1341 },
1342 {
1343 .name = "wm831x-aldo",
1344 .id = 8,
1345 .num_resources = ARRAY_SIZE(wm831x_ldo8_resources),
1346 .resources = wm831x_ldo8_resources,
1347 },
1348 {
1349 .name = "wm831x-aldo",
1350 .id = 9,
1351 .num_resources = ARRAY_SIZE(wm831x_ldo9_resources),
1352 .resources = wm831x_ldo9_resources,
1353 },
1354 {
1355 .name = "wm831x-aldo",
1356 .id = 10,
1357 .num_resources = ARRAY_SIZE(wm831x_ldo10_resources),
1358 .resources = wm831x_ldo10_resources,
1359 },
1360 {
1361 .name = "wm831x-alive-ldo",
1362 .id = 11,
1363 .num_resources = ARRAY_SIZE(wm831x_ldo11_resources),
1364 .resources = wm831x_ldo11_resources,
1365 },
1366 {
1367 .name = "wm831x-on",
1368 .num_resources = ARRAY_SIZE(wm831x_on_resources),
1369 .resources = wm831x_on_resources,
1370 },
1371 {
1372 .name = "wm831x-rtc",
1373 .num_resources = ARRAY_SIZE(wm831x_rtc_resources),
1374 .resources = wm831x_rtc_resources,
1375 },
1376 {
1377 .name = "wm831x-status",
1378 .id = 1,
1379 .num_resources = ARRAY_SIZE(wm831x_status1_resources),
1380 .resources = wm831x_status1_resources,
1381 },
1382 {
1383 .name = "wm831x-status",
1384 .id = 2,
1385 .num_resources = ARRAY_SIZE(wm831x_status2_resources),
1386 .resources = wm831x_status2_resources,
1387 },
1388 {
1389 .name = "wm831x-watchdog",
1390 .num_resources = ARRAY_SIZE(wm831x_wdt_resources),
1391 .resources = wm831x_wdt_resources,
1392 },
1393};
1394
Mark Brown63aed852009-07-27 14:45:55 +01001395static struct mfd_cell backlight_devs[] = {
1396 {
1397 .name = "wm831x-backlight",
1398 },
1399};
1400
Mark Brownd2bedfe2009-07-27 14:45:52 +01001401/*
1402 * Instantiate the generic non-control parts of the device.
1403 */
1404static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
1405{
1406 struct wm831x_pdata *pdata = wm831x->dev->platform_data;
1407 int rev;
1408 enum wm831x_parent parent;
1409 int ret;
1410
1411 mutex_init(&wm831x->io_lock);
1412 mutex_init(&wm831x->key_lock);
Mark Brown7e9f9fd2009-07-27 14:45:54 +01001413 mutex_init(&wm831x->auxadc_lock);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001414 dev_set_drvdata(wm831x->dev, wm831x);
1415
1416 ret = wm831x_reg_read(wm831x, WM831X_PARENT_ID);
1417 if (ret < 0) {
1418 dev_err(wm831x->dev, "Failed to read parent ID: %d\n", ret);
1419 goto err;
1420 }
1421 if (ret != 0x6204) {
1422 dev_err(wm831x->dev, "Device is not a WM831x: ID %x\n", ret);
1423 ret = -EINVAL;
1424 goto err;
1425 }
1426
1427 ret = wm831x_reg_read(wm831x, WM831X_REVISION);
1428 if (ret < 0) {
1429 dev_err(wm831x->dev, "Failed to read revision: %d\n", ret);
1430 goto err;
1431 }
1432 rev = (ret & WM831X_PARENT_REV_MASK) >> WM831X_PARENT_REV_SHIFT;
1433
1434 ret = wm831x_reg_read(wm831x, WM831X_RESET_ID);
1435 if (ret < 0) {
1436 dev_err(wm831x->dev, "Failed to read device ID: %d\n", ret);
1437 goto err;
1438 }
1439
Mark Brown894362f2009-10-01 15:41:04 +01001440 /* Some engineering samples do not have the ID set, rely on
1441 * the device being registered correctly.
1442 */
1443 if (ret == 0) {
1444 dev_info(wm831x->dev, "Device is an engineering sample\n");
1445 ret = id;
1446 }
1447
Mark Brownd2bedfe2009-07-27 14:45:52 +01001448 switch (ret) {
Mark Brown894362f2009-10-01 15:41:04 +01001449 case WM8310:
Mark Brownd2bedfe2009-07-27 14:45:52 +01001450 parent = WM8310;
Mark Brown6f2ecaae2009-10-01 15:41:05 +01001451 wm831x->num_gpio = 16;
Mark Brown894362f2009-10-01 15:41:04 +01001452 dev_info(wm831x->dev, "WM8310 revision %c\n", 'A' + rev);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001453 break;
1454
Mark Brown894362f2009-10-01 15:41:04 +01001455 case WM8311:
Mark Brownd2bedfe2009-07-27 14:45:52 +01001456 parent = WM8311;
Mark Brown6f2ecaae2009-10-01 15:41:05 +01001457 wm831x->num_gpio = 16;
Mark Brown894362f2009-10-01 15:41:04 +01001458 dev_info(wm831x->dev, "WM8311 revision %c\n", 'A' + rev);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001459 break;
1460
Mark Brown894362f2009-10-01 15:41:04 +01001461 case WM8312:
Mark Brownd2bedfe2009-07-27 14:45:52 +01001462 parent = WM8312;
Mark Brown6f2ecaae2009-10-01 15:41:05 +01001463 wm831x->num_gpio = 16;
Mark Brown894362f2009-10-01 15:41:04 +01001464 dev_info(wm831x->dev, "WM8312 revision %c\n", 'A' + rev);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001465 break;
1466
Mark Brownd4e0a892009-10-01 15:41:07 +01001467 case WM8320:
1468 parent = WM8320;
1469 wm831x->num_gpio = 12;
1470 dev_info(wm831x->dev, "WM8320 revision %c\n", 'A' + rev);
1471 break;
1472
Mark Brownd2bedfe2009-07-27 14:45:52 +01001473 default:
1474 dev_err(wm831x->dev, "Unknown WM831x device %04x\n", ret);
1475 ret = -EINVAL;
1476 goto err;
1477 }
1478
1479 /* This will need revisiting in future but is OK for all
1480 * current parts.
1481 */
1482 if (parent != id)
Mark Brown894362f2009-10-01 15:41:04 +01001483 dev_warn(wm831x->dev, "Device was registered as a WM%lx\n",
Mark Brownd2bedfe2009-07-27 14:45:52 +01001484 id);
1485
1486 /* Bootstrap the user key */
1487 ret = wm831x_reg_read(wm831x, WM831X_SECURITY_KEY);
1488 if (ret < 0) {
1489 dev_err(wm831x->dev, "Failed to read security key: %d\n", ret);
1490 goto err;
1491 }
1492 if (ret != 0) {
1493 dev_warn(wm831x->dev, "Security key had non-zero value %x\n",
1494 ret);
1495 wm831x_reg_write(wm831x, WM831X_SECURITY_KEY, 0);
1496 }
1497 wm831x->locked = 1;
1498
1499 if (pdata && pdata->pre_init) {
1500 ret = pdata->pre_init(wm831x);
1501 if (ret != 0) {
1502 dev_err(wm831x->dev, "pre_init() failed: %d\n", ret);
1503 goto err;
1504 }
1505 }
1506
Mark Brown7d4d0a32009-07-27 14:45:53 +01001507 ret = wm831x_irq_init(wm831x, irq);
1508 if (ret != 0)
1509 goto err;
1510
Mark Brownd2bedfe2009-07-27 14:45:52 +01001511 /* The core device is up, instantiate the subdevices. */
1512 switch (parent) {
1513 case WM8310:
1514 ret = mfd_add_devices(wm831x->dev, -1,
1515 wm8310_devs, ARRAY_SIZE(wm8310_devs),
Mark Brown5fb4d382009-11-11 16:10:22 +00001516 NULL, wm831x->irq_base);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001517 break;
1518
1519 case WM8311:
1520 ret = mfd_add_devices(wm831x->dev, -1,
1521 wm8311_devs, ARRAY_SIZE(wm8311_devs),
Mark Brown5fb4d382009-11-11 16:10:22 +00001522 NULL, wm831x->irq_base);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001523 break;
1524
1525 case WM8312:
1526 ret = mfd_add_devices(wm831x->dev, -1,
1527 wm8312_devs, ARRAY_SIZE(wm8312_devs),
Mark Brown5fb4d382009-11-11 16:10:22 +00001528 NULL, wm831x->irq_base);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001529 break;
1530
Mark Brownd4e0a892009-10-01 15:41:07 +01001531 case WM8320:
1532 ret = mfd_add_devices(wm831x->dev, -1,
1533 wm8320_devs, ARRAY_SIZE(wm8320_devs),
1534 NULL, 0);
1535 break;
1536
Mark Brownd2bedfe2009-07-27 14:45:52 +01001537 default:
1538 /* If this happens the bus probe function is buggy */
1539 BUG();
1540 }
1541
1542 if (ret != 0) {
1543 dev_err(wm831x->dev, "Failed to add children\n");
Mark Brown7d4d0a32009-07-27 14:45:53 +01001544 goto err_irq;
Mark Brownd2bedfe2009-07-27 14:45:52 +01001545 }
1546
Mark Brown63aed852009-07-27 14:45:55 +01001547 if (pdata && pdata->backlight) {
1548 /* Treat errors as non-critical */
1549 ret = mfd_add_devices(wm831x->dev, -1, backlight_devs,
Mark Brown5fb4d382009-11-11 16:10:22 +00001550 ARRAY_SIZE(backlight_devs), NULL,
1551 wm831x->irq_base);
Mark Brown63aed852009-07-27 14:45:55 +01001552 if (ret < 0)
1553 dev_err(wm831x->dev, "Failed to add backlight: %d\n",
1554 ret);
1555 }
1556
Mark Brown6704e512009-07-27 14:45:56 +01001557 wm831x_otp_init(wm831x);
1558
Mark Brownd2bedfe2009-07-27 14:45:52 +01001559 if (pdata && pdata->post_init) {
1560 ret = pdata->post_init(wm831x);
1561 if (ret != 0) {
1562 dev_err(wm831x->dev, "post_init() failed: %d\n", ret);
Mark Brown7d4d0a32009-07-27 14:45:53 +01001563 goto err_irq;
Mark Brownd2bedfe2009-07-27 14:45:52 +01001564 }
1565 }
1566
1567 return 0;
1568
Mark Brown7d4d0a32009-07-27 14:45:53 +01001569err_irq:
1570 wm831x_irq_exit(wm831x);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001571err:
1572 mfd_remove_devices(wm831x->dev);
1573 kfree(wm831x);
1574 return ret;
1575}
1576
1577static void wm831x_device_exit(struct wm831x *wm831x)
1578{
Mark Brown6704e512009-07-27 14:45:56 +01001579 wm831x_otp_exit(wm831x);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001580 mfd_remove_devices(wm831x->dev);
Mark Brown7d4d0a32009-07-27 14:45:53 +01001581 wm831x_irq_exit(wm831x);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001582 kfree(wm831x);
1583}
1584
1585static int wm831x_i2c_read_device(struct wm831x *wm831x, unsigned short reg,
1586 int bytes, void *dest)
1587{
1588 struct i2c_client *i2c = wm831x->control_data;
1589 int ret;
1590 u16 r = cpu_to_be16(reg);
1591
1592 ret = i2c_master_send(i2c, (unsigned char *)&r, 2);
1593 if (ret < 0)
1594 return ret;
1595 if (ret != 2)
1596 return -EIO;
1597
1598 ret = i2c_master_recv(i2c, dest, bytes);
1599 if (ret < 0)
1600 return ret;
1601 if (ret != bytes)
1602 return -EIO;
1603 return 0;
1604}
1605
1606/* Currently we allocate the write buffer on the stack; this is OK for
1607 * small writes - if we need to do large writes this will need to be
1608 * revised.
1609 */
1610static int wm831x_i2c_write_device(struct wm831x *wm831x, unsigned short reg,
1611 int bytes, void *src)
1612{
1613 struct i2c_client *i2c = wm831x->control_data;
1614 unsigned char msg[bytes + 2];
1615 int ret;
1616
1617 reg = cpu_to_be16(reg);
1618 memcpy(&msg[0], &reg, 2);
1619 memcpy(&msg[2], src, bytes);
1620
1621 ret = i2c_master_send(i2c, msg, bytes + 2);
1622 if (ret < 0)
1623 return ret;
1624 if (ret < bytes + 2)
1625 return -EIO;
1626
1627 return 0;
1628}
1629
1630static int wm831x_i2c_probe(struct i2c_client *i2c,
1631 const struct i2c_device_id *id)
1632{
1633 struct wm831x *wm831x;
1634
1635 wm831x = kzalloc(sizeof(struct wm831x), GFP_KERNEL);
1636 if (wm831x == NULL) {
1637 kfree(i2c);
1638 return -ENOMEM;
1639 }
1640
1641 i2c_set_clientdata(i2c, wm831x);
1642 wm831x->dev = &i2c->dev;
1643 wm831x->control_data = i2c;
1644 wm831x->read_dev = wm831x_i2c_read_device;
1645 wm831x->write_dev = wm831x_i2c_write_device;
1646
1647 return wm831x_device_init(wm831x, id->driver_data, i2c->irq);
1648}
1649
1650static int wm831x_i2c_remove(struct i2c_client *i2c)
1651{
1652 struct wm831x *wm831x = i2c_get_clientdata(i2c);
1653
1654 wm831x_device_exit(wm831x);
1655
1656 return 0;
1657}
1658
1659static const struct i2c_device_id wm831x_i2c_id[] = {
1660 { "wm8310", WM8310 },
1661 { "wm8311", WM8311 },
1662 { "wm8312", WM8312 },
Mark Brownd4e0a892009-10-01 15:41:07 +01001663 { "wm8320", WM8320 },
Mark Brownd2bedfe2009-07-27 14:45:52 +01001664 { }
1665};
1666MODULE_DEVICE_TABLE(i2c, wm831x_i2c_id);
1667
1668
1669static struct i2c_driver wm831x_i2c_driver = {
1670 .driver = {
1671 .name = "wm831x",
1672 .owner = THIS_MODULE,
1673 },
1674 .probe = wm831x_i2c_probe,
1675 .remove = wm831x_i2c_remove,
1676 .id_table = wm831x_i2c_id,
1677};
1678
1679static int __init wm831x_i2c_init(void)
1680{
1681 int ret;
1682
1683 ret = i2c_add_driver(&wm831x_i2c_driver);
1684 if (ret != 0)
1685 pr_err("Failed to register wm831x I2C driver: %d\n", ret);
1686
1687 return ret;
1688}
1689subsys_initcall(wm831x_i2c_init);
1690
1691static void __exit wm831x_i2c_exit(void)
1692{
1693 i2c_del_driver(&wm831x_i2c_driver);
1694}
1695module_exit(wm831x_i2c_exit);
1696
1697MODULE_DESCRIPTION("I2C support for the WM831X AudioPlus PMIC");
1698MODULE_LICENSE("GPL");
1699MODULE_AUTHOR("Mark Brown");