blob: 07101e9e1cba14dfc71aaaf4f9300c2660c3e032 [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{
Mark Brown7e9f9fd2009-07-27 14:45:54 +0100324 int ret, src;
325
326 mutex_lock(&wm831x->auxadc_lock);
327
328 ret = wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL,
329 WM831X_AUX_ENA, WM831X_AUX_ENA);
330 if (ret < 0) {
331 dev_err(wm831x->dev, "Failed to enable AUXADC: %d\n", ret);
332 goto out;
333 }
334
335 /* We force a single source at present */
336 src = input;
337 ret = wm831x_reg_write(wm831x, WM831X_AUXADC_SOURCE,
338 1 << src);
339 if (ret < 0) {
340 dev_err(wm831x->dev, "Failed to set AUXADC source: %d\n", ret);
341 goto out;
342 }
343
344 ret = wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL,
345 WM831X_AUX_CVT_ENA, WM831X_AUX_CVT_ENA);
346 if (ret < 0) {
347 dev_err(wm831x->dev, "Failed to start AUXADC: %d\n", ret);
348 goto disable;
349 }
350
Mark Brown473fe732010-02-23 11:08:06 +0000351 /* Ignore the result to allow us to soldier on without IRQ hookup */
352 wait_for_completion_timeout(&wm831x->auxadc_done, msecs_to_jiffies(5));
Mark Brown7e9f9fd2009-07-27 14:45:54 +0100353
Mark Brown473fe732010-02-23 11:08:06 +0000354 ret = wm831x_reg_read(wm831x, WM831X_AUXADC_CONTROL);
355 if (ret < 0) {
356 dev_err(wm831x->dev, "AUXADC status read failed: %d\n", ret);
357 goto disable;
358 }
Mark Brown7e9f9fd2009-07-27 14:45:54 +0100359
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
Mark Brown473fe732010-02-23 11:08:06 +0000393static irqreturn_t wm831x_auxadc_irq(int irq, void *irq_data)
394{
395 struct wm831x *wm831x = irq_data;
396
397 complete(&wm831x->auxadc_done);
398
399 return IRQ_HANDLED;
400}
401
Mark Brown7e9f9fd2009-07-27 14:45:54 +0100402/**
403 * wm831x_auxadc_read_uv: Read a voltage from the WM831x AUXADC
404 *
405 * @wm831x: Device to read from.
406 * @input: AUXADC input to read.
407 */
408int wm831x_auxadc_read_uv(struct wm831x *wm831x, enum wm831x_auxadc input)
409{
410 int ret;
411
412 ret = wm831x_auxadc_read(wm831x, input);
413 if (ret < 0)
414 return ret;
415
416 ret *= 1465;
417
418 return ret;
419}
420EXPORT_SYMBOL_GPL(wm831x_auxadc_read_uv);
421
Mark Brownd2bedfe2009-07-27 14:45:52 +0100422static struct resource wm831x_dcdc1_resources[] = {
423 {
424 .start = WM831X_DC1_CONTROL_1,
425 .end = WM831X_DC1_DVS_CONTROL,
426 .flags = IORESOURCE_IO,
427 },
428 {
429 .name = "UV",
430 .start = WM831X_IRQ_UV_DC1,
431 .end = WM831X_IRQ_UV_DC1,
432 .flags = IORESOURCE_IRQ,
433 },
434 {
435 .name = "HC",
436 .start = WM831X_IRQ_HC_DC1,
437 .end = WM831X_IRQ_HC_DC1,
438 .flags = IORESOURCE_IRQ,
439 },
440};
441
442
443static struct resource wm831x_dcdc2_resources[] = {
444 {
445 .start = WM831X_DC2_CONTROL_1,
446 .end = WM831X_DC2_DVS_CONTROL,
447 .flags = IORESOURCE_IO,
448 },
449 {
450 .name = "UV",
451 .start = WM831X_IRQ_UV_DC2,
452 .end = WM831X_IRQ_UV_DC2,
453 .flags = IORESOURCE_IRQ,
454 },
455 {
456 .name = "HC",
457 .start = WM831X_IRQ_HC_DC2,
458 .end = WM831X_IRQ_HC_DC2,
459 .flags = IORESOURCE_IRQ,
460 },
461};
462
463static struct resource wm831x_dcdc3_resources[] = {
464 {
465 .start = WM831X_DC3_CONTROL_1,
466 .end = WM831X_DC3_SLEEP_CONTROL,
467 .flags = IORESOURCE_IO,
468 },
469 {
470 .name = "UV",
471 .start = WM831X_IRQ_UV_DC3,
472 .end = WM831X_IRQ_UV_DC3,
473 .flags = IORESOURCE_IRQ,
474 },
475};
476
477static struct resource wm831x_dcdc4_resources[] = {
478 {
479 .start = WM831X_DC4_CONTROL,
480 .end = WM831X_DC4_SLEEP_CONTROL,
481 .flags = IORESOURCE_IO,
482 },
483 {
484 .name = "UV",
485 .start = WM831X_IRQ_UV_DC4,
486 .end = WM831X_IRQ_UV_DC4,
487 .flags = IORESOURCE_IRQ,
488 },
489};
490
Mark Brownd4e0a892009-10-01 15:41:07 +0100491static struct resource wm8320_dcdc4_buck_resources[] = {
492 {
493 .start = WM831X_DC4_CONTROL,
494 .end = WM832X_DC4_SLEEP_CONTROL,
495 .flags = IORESOURCE_IO,
496 },
497 {
498 .name = "UV",
499 .start = WM831X_IRQ_UV_DC4,
500 .end = WM831X_IRQ_UV_DC4,
501 .flags = IORESOURCE_IRQ,
502 },
503};
504
Mark Brownd2bedfe2009-07-27 14:45:52 +0100505static struct resource wm831x_gpio_resources[] = {
506 {
507 .start = WM831X_IRQ_GPIO_1,
508 .end = WM831X_IRQ_GPIO_16,
509 .flags = IORESOURCE_IRQ,
510 },
511};
512
513static struct resource wm831x_isink1_resources[] = {
514 {
515 .start = WM831X_CURRENT_SINK_1,
516 .end = WM831X_CURRENT_SINK_1,
517 .flags = IORESOURCE_IO,
518 },
519 {
520 .start = WM831X_IRQ_CS1,
521 .end = WM831X_IRQ_CS1,
522 .flags = IORESOURCE_IRQ,
523 },
524};
525
526static struct resource wm831x_isink2_resources[] = {
527 {
528 .start = WM831X_CURRENT_SINK_2,
529 .end = WM831X_CURRENT_SINK_2,
530 .flags = IORESOURCE_IO,
531 },
532 {
533 .start = WM831X_IRQ_CS2,
534 .end = WM831X_IRQ_CS2,
535 .flags = IORESOURCE_IRQ,
536 },
537};
538
539static struct resource wm831x_ldo1_resources[] = {
540 {
541 .start = WM831X_LDO1_CONTROL,
542 .end = WM831X_LDO1_SLEEP_CONTROL,
543 .flags = IORESOURCE_IO,
544 },
545 {
546 .name = "UV",
547 .start = WM831X_IRQ_UV_LDO1,
548 .end = WM831X_IRQ_UV_LDO1,
549 .flags = IORESOURCE_IRQ,
550 },
551};
552
553static struct resource wm831x_ldo2_resources[] = {
554 {
555 .start = WM831X_LDO2_CONTROL,
556 .end = WM831X_LDO2_SLEEP_CONTROL,
557 .flags = IORESOURCE_IO,
558 },
559 {
560 .name = "UV",
561 .start = WM831X_IRQ_UV_LDO2,
562 .end = WM831X_IRQ_UV_LDO2,
563 .flags = IORESOURCE_IRQ,
564 },
565};
566
567static struct resource wm831x_ldo3_resources[] = {
568 {
569 .start = WM831X_LDO3_CONTROL,
570 .end = WM831X_LDO3_SLEEP_CONTROL,
571 .flags = IORESOURCE_IO,
572 },
573 {
574 .name = "UV",
575 .start = WM831X_IRQ_UV_LDO3,
576 .end = WM831X_IRQ_UV_LDO3,
577 .flags = IORESOURCE_IRQ,
578 },
579};
580
581static struct resource wm831x_ldo4_resources[] = {
582 {
583 .start = WM831X_LDO4_CONTROL,
584 .end = WM831X_LDO4_SLEEP_CONTROL,
585 .flags = IORESOURCE_IO,
586 },
587 {
588 .name = "UV",
589 .start = WM831X_IRQ_UV_LDO4,
590 .end = WM831X_IRQ_UV_LDO4,
591 .flags = IORESOURCE_IRQ,
592 },
593};
594
595static struct resource wm831x_ldo5_resources[] = {
596 {
597 .start = WM831X_LDO5_CONTROL,
598 .end = WM831X_LDO5_SLEEP_CONTROL,
599 .flags = IORESOURCE_IO,
600 },
601 {
602 .name = "UV",
603 .start = WM831X_IRQ_UV_LDO5,
604 .end = WM831X_IRQ_UV_LDO5,
605 .flags = IORESOURCE_IRQ,
606 },
607};
608
609static struct resource wm831x_ldo6_resources[] = {
610 {
611 .start = WM831X_LDO6_CONTROL,
612 .end = WM831X_LDO6_SLEEP_CONTROL,
613 .flags = IORESOURCE_IO,
614 },
615 {
616 .name = "UV",
617 .start = WM831X_IRQ_UV_LDO6,
618 .end = WM831X_IRQ_UV_LDO6,
619 .flags = IORESOURCE_IRQ,
620 },
621};
622
623static struct resource wm831x_ldo7_resources[] = {
624 {
625 .start = WM831X_LDO7_CONTROL,
626 .end = WM831X_LDO7_SLEEP_CONTROL,
627 .flags = IORESOURCE_IO,
628 },
629 {
630 .name = "UV",
631 .start = WM831X_IRQ_UV_LDO7,
632 .end = WM831X_IRQ_UV_LDO7,
633 .flags = IORESOURCE_IRQ,
634 },
635};
636
637static struct resource wm831x_ldo8_resources[] = {
638 {
639 .start = WM831X_LDO8_CONTROL,
640 .end = WM831X_LDO8_SLEEP_CONTROL,
641 .flags = IORESOURCE_IO,
642 },
643 {
644 .name = "UV",
645 .start = WM831X_IRQ_UV_LDO8,
646 .end = WM831X_IRQ_UV_LDO8,
647 .flags = IORESOURCE_IRQ,
648 },
649};
650
651static struct resource wm831x_ldo9_resources[] = {
652 {
653 .start = WM831X_LDO9_CONTROL,
654 .end = WM831X_LDO9_SLEEP_CONTROL,
655 .flags = IORESOURCE_IO,
656 },
657 {
658 .name = "UV",
659 .start = WM831X_IRQ_UV_LDO9,
660 .end = WM831X_IRQ_UV_LDO9,
661 .flags = IORESOURCE_IRQ,
662 },
663};
664
665static struct resource wm831x_ldo10_resources[] = {
666 {
667 .start = WM831X_LDO10_CONTROL,
668 .end = WM831X_LDO10_SLEEP_CONTROL,
669 .flags = IORESOURCE_IO,
670 },
671 {
672 .name = "UV",
673 .start = WM831X_IRQ_UV_LDO10,
674 .end = WM831X_IRQ_UV_LDO10,
675 .flags = IORESOURCE_IRQ,
676 },
677};
678
679static struct resource wm831x_ldo11_resources[] = {
680 {
681 .start = WM831X_LDO11_ON_CONTROL,
682 .end = WM831X_LDO11_SLEEP_CONTROL,
683 .flags = IORESOURCE_IO,
684 },
685};
686
687static struct resource wm831x_on_resources[] = {
688 {
689 .start = WM831X_IRQ_ON,
690 .end = WM831X_IRQ_ON,
691 .flags = IORESOURCE_IRQ,
692 },
693};
694
695
696static struct resource wm831x_power_resources[] = {
697 {
698 .name = "SYSLO",
699 .start = WM831X_IRQ_PPM_SYSLO,
700 .end = WM831X_IRQ_PPM_SYSLO,
701 .flags = IORESOURCE_IRQ,
702 },
703 {
704 .name = "PWR SRC",
705 .start = WM831X_IRQ_PPM_PWR_SRC,
706 .end = WM831X_IRQ_PPM_PWR_SRC,
707 .flags = IORESOURCE_IRQ,
708 },
709 {
710 .name = "USB CURR",
711 .start = WM831X_IRQ_PPM_USB_CURR,
712 .end = WM831X_IRQ_PPM_USB_CURR,
713 .flags = IORESOURCE_IRQ,
714 },
715 {
716 .name = "BATT HOT",
717 .start = WM831X_IRQ_CHG_BATT_HOT,
718 .end = WM831X_IRQ_CHG_BATT_HOT,
719 .flags = IORESOURCE_IRQ,
720 },
721 {
722 .name = "BATT COLD",
723 .start = WM831X_IRQ_CHG_BATT_COLD,
724 .end = WM831X_IRQ_CHG_BATT_COLD,
725 .flags = IORESOURCE_IRQ,
726 },
727 {
728 .name = "BATT FAIL",
729 .start = WM831X_IRQ_CHG_BATT_FAIL,
730 .end = WM831X_IRQ_CHG_BATT_FAIL,
731 .flags = IORESOURCE_IRQ,
732 },
733 {
734 .name = "OV",
735 .start = WM831X_IRQ_CHG_OV,
736 .end = WM831X_IRQ_CHG_OV,
737 .flags = IORESOURCE_IRQ,
738 },
739 {
740 .name = "END",
741 .start = WM831X_IRQ_CHG_END,
742 .end = WM831X_IRQ_CHG_END,
743 .flags = IORESOURCE_IRQ,
744 },
745 {
746 .name = "TO",
747 .start = WM831X_IRQ_CHG_TO,
748 .end = WM831X_IRQ_CHG_TO,
749 .flags = IORESOURCE_IRQ,
750 },
751 {
752 .name = "MODE",
753 .start = WM831X_IRQ_CHG_MODE,
754 .end = WM831X_IRQ_CHG_MODE,
755 .flags = IORESOURCE_IRQ,
756 },
757 {
758 .name = "START",
759 .start = WM831X_IRQ_CHG_START,
760 .end = WM831X_IRQ_CHG_START,
761 .flags = IORESOURCE_IRQ,
762 },
763};
764
765static struct resource wm831x_rtc_resources[] = {
766 {
767 .name = "PER",
768 .start = WM831X_IRQ_RTC_PER,
769 .end = WM831X_IRQ_RTC_PER,
770 .flags = IORESOURCE_IRQ,
771 },
772 {
773 .name = "ALM",
774 .start = WM831X_IRQ_RTC_ALM,
775 .end = WM831X_IRQ_RTC_ALM,
776 .flags = IORESOURCE_IRQ,
777 },
778};
779
780static struct resource wm831x_status1_resources[] = {
781 {
782 .start = WM831X_STATUS_LED_1,
783 .end = WM831X_STATUS_LED_1,
784 .flags = IORESOURCE_IO,
785 },
786};
787
788static struct resource wm831x_status2_resources[] = {
789 {
790 .start = WM831X_STATUS_LED_2,
791 .end = WM831X_STATUS_LED_2,
792 .flags = IORESOURCE_IO,
793 },
794};
795
796static struct resource wm831x_touch_resources[] = {
797 {
798 .name = "TCHPD",
799 .start = WM831X_IRQ_TCHPD,
800 .end = WM831X_IRQ_TCHPD,
801 .flags = IORESOURCE_IRQ,
802 },
803 {
804 .name = "TCHDATA",
805 .start = WM831X_IRQ_TCHDATA,
806 .end = WM831X_IRQ_TCHDATA,
807 .flags = IORESOURCE_IRQ,
808 },
809};
810
811static struct resource wm831x_wdt_resources[] = {
812 {
813 .start = WM831X_IRQ_WDOG_TO,
814 .end = WM831X_IRQ_WDOG_TO,
815 .flags = IORESOURCE_IRQ,
816 },
817};
818
819static struct mfd_cell wm8310_devs[] = {
820 {
Mark Brownc26964e2009-10-01 15:41:06 +0100821 .name = "wm831x-backup",
822 },
823 {
Mark Brownd2bedfe2009-07-27 14:45:52 +0100824 .name = "wm831x-buckv",
825 .id = 1,
826 .num_resources = ARRAY_SIZE(wm831x_dcdc1_resources),
827 .resources = wm831x_dcdc1_resources,
828 },
829 {
830 .name = "wm831x-buckv",
831 .id = 2,
832 .num_resources = ARRAY_SIZE(wm831x_dcdc2_resources),
833 .resources = wm831x_dcdc2_resources,
834 },
835 {
836 .name = "wm831x-buckp",
837 .id = 3,
838 .num_resources = ARRAY_SIZE(wm831x_dcdc3_resources),
839 .resources = wm831x_dcdc3_resources,
840 },
841 {
842 .name = "wm831x-boostp",
843 .id = 4,
844 .num_resources = ARRAY_SIZE(wm831x_dcdc4_resources),
845 .resources = wm831x_dcdc4_resources,
846 },
847 {
848 .name = "wm831x-epe",
849 .id = 1,
850 },
851 {
852 .name = "wm831x-epe",
853 .id = 2,
854 },
855 {
856 .name = "wm831x-gpio",
857 .num_resources = ARRAY_SIZE(wm831x_gpio_resources),
858 .resources = wm831x_gpio_resources,
859 },
860 {
861 .name = "wm831x-hwmon",
862 },
863 {
864 .name = "wm831x-isink",
865 .id = 1,
866 .num_resources = ARRAY_SIZE(wm831x_isink1_resources),
867 .resources = wm831x_isink1_resources,
868 },
869 {
870 .name = "wm831x-isink",
871 .id = 2,
872 .num_resources = ARRAY_SIZE(wm831x_isink2_resources),
873 .resources = wm831x_isink2_resources,
874 },
875 {
876 .name = "wm831x-ldo",
877 .id = 1,
878 .num_resources = ARRAY_SIZE(wm831x_ldo1_resources),
879 .resources = wm831x_ldo1_resources,
880 },
881 {
882 .name = "wm831x-ldo",
883 .id = 2,
884 .num_resources = ARRAY_SIZE(wm831x_ldo2_resources),
885 .resources = wm831x_ldo2_resources,
886 },
887 {
888 .name = "wm831x-ldo",
889 .id = 3,
890 .num_resources = ARRAY_SIZE(wm831x_ldo3_resources),
891 .resources = wm831x_ldo3_resources,
892 },
893 {
894 .name = "wm831x-ldo",
895 .id = 4,
896 .num_resources = ARRAY_SIZE(wm831x_ldo4_resources),
897 .resources = wm831x_ldo4_resources,
898 },
899 {
900 .name = "wm831x-ldo",
901 .id = 5,
902 .num_resources = ARRAY_SIZE(wm831x_ldo5_resources),
903 .resources = wm831x_ldo5_resources,
904 },
905 {
906 .name = "wm831x-ldo",
907 .id = 6,
908 .num_resources = ARRAY_SIZE(wm831x_ldo6_resources),
909 .resources = wm831x_ldo6_resources,
910 },
911 {
912 .name = "wm831x-aldo",
913 .id = 7,
914 .num_resources = ARRAY_SIZE(wm831x_ldo7_resources),
915 .resources = wm831x_ldo7_resources,
916 },
917 {
918 .name = "wm831x-aldo",
919 .id = 8,
920 .num_resources = ARRAY_SIZE(wm831x_ldo8_resources),
921 .resources = wm831x_ldo8_resources,
922 },
923 {
924 .name = "wm831x-aldo",
925 .id = 9,
926 .num_resources = ARRAY_SIZE(wm831x_ldo9_resources),
927 .resources = wm831x_ldo9_resources,
928 },
929 {
930 .name = "wm831x-aldo",
931 .id = 10,
932 .num_resources = ARRAY_SIZE(wm831x_ldo10_resources),
933 .resources = wm831x_ldo10_resources,
934 },
935 {
936 .name = "wm831x-alive-ldo",
937 .id = 11,
938 .num_resources = ARRAY_SIZE(wm831x_ldo11_resources),
939 .resources = wm831x_ldo11_resources,
940 },
941 {
942 .name = "wm831x-on",
943 .num_resources = ARRAY_SIZE(wm831x_on_resources),
944 .resources = wm831x_on_resources,
945 },
946 {
947 .name = "wm831x-power",
948 .num_resources = ARRAY_SIZE(wm831x_power_resources),
949 .resources = wm831x_power_resources,
950 },
951 {
952 .name = "wm831x-rtc",
953 .num_resources = ARRAY_SIZE(wm831x_rtc_resources),
954 .resources = wm831x_rtc_resources,
955 },
956 {
957 .name = "wm831x-status",
958 .id = 1,
959 .num_resources = ARRAY_SIZE(wm831x_status1_resources),
960 .resources = wm831x_status1_resources,
961 },
962 {
963 .name = "wm831x-status",
964 .id = 2,
965 .num_resources = ARRAY_SIZE(wm831x_status2_resources),
966 .resources = wm831x_status2_resources,
967 },
968 {
969 .name = "wm831x-watchdog",
970 .num_resources = ARRAY_SIZE(wm831x_wdt_resources),
971 .resources = wm831x_wdt_resources,
972 },
973};
974
975static struct mfd_cell wm8311_devs[] = {
976 {
Mark Brownc26964e2009-10-01 15:41:06 +0100977 .name = "wm831x-backup",
978 },
979 {
Mark Brownd2bedfe2009-07-27 14:45:52 +0100980 .name = "wm831x-buckv",
981 .id = 1,
982 .num_resources = ARRAY_SIZE(wm831x_dcdc1_resources),
983 .resources = wm831x_dcdc1_resources,
984 },
985 {
986 .name = "wm831x-buckv",
987 .id = 2,
988 .num_resources = ARRAY_SIZE(wm831x_dcdc2_resources),
989 .resources = wm831x_dcdc2_resources,
990 },
991 {
992 .name = "wm831x-buckp",
993 .id = 3,
994 .num_resources = ARRAY_SIZE(wm831x_dcdc3_resources),
995 .resources = wm831x_dcdc3_resources,
996 },
997 {
998 .name = "wm831x-boostp",
999 .id = 4,
1000 .num_resources = ARRAY_SIZE(wm831x_dcdc4_resources),
1001 .resources = wm831x_dcdc4_resources,
1002 },
1003 {
1004 .name = "wm831x-epe",
1005 .id = 1,
1006 },
1007 {
1008 .name = "wm831x-epe",
1009 .id = 2,
1010 },
1011 {
1012 .name = "wm831x-gpio",
1013 .num_resources = ARRAY_SIZE(wm831x_gpio_resources),
1014 .resources = wm831x_gpio_resources,
1015 },
1016 {
1017 .name = "wm831x-hwmon",
1018 },
1019 {
1020 .name = "wm831x-isink",
1021 .id = 1,
1022 .num_resources = ARRAY_SIZE(wm831x_isink1_resources),
1023 .resources = wm831x_isink1_resources,
1024 },
1025 {
1026 .name = "wm831x-isink",
1027 .id = 2,
1028 .num_resources = ARRAY_SIZE(wm831x_isink2_resources),
1029 .resources = wm831x_isink2_resources,
1030 },
1031 {
1032 .name = "wm831x-ldo",
1033 .id = 1,
1034 .num_resources = ARRAY_SIZE(wm831x_ldo1_resources),
1035 .resources = wm831x_ldo1_resources,
1036 },
1037 {
1038 .name = "wm831x-ldo",
1039 .id = 2,
1040 .num_resources = ARRAY_SIZE(wm831x_ldo2_resources),
1041 .resources = wm831x_ldo2_resources,
1042 },
1043 {
1044 .name = "wm831x-ldo",
1045 .id = 3,
1046 .num_resources = ARRAY_SIZE(wm831x_ldo3_resources),
1047 .resources = wm831x_ldo3_resources,
1048 },
1049 {
1050 .name = "wm831x-ldo",
1051 .id = 4,
1052 .num_resources = ARRAY_SIZE(wm831x_ldo4_resources),
1053 .resources = wm831x_ldo4_resources,
1054 },
1055 {
1056 .name = "wm831x-ldo",
1057 .id = 5,
1058 .num_resources = ARRAY_SIZE(wm831x_ldo5_resources),
1059 .resources = wm831x_ldo5_resources,
1060 },
1061 {
1062 .name = "wm831x-aldo",
1063 .id = 7,
1064 .num_resources = ARRAY_SIZE(wm831x_ldo7_resources),
1065 .resources = wm831x_ldo7_resources,
1066 },
1067 {
1068 .name = "wm831x-alive-ldo",
1069 .id = 11,
1070 .num_resources = ARRAY_SIZE(wm831x_ldo11_resources),
1071 .resources = wm831x_ldo11_resources,
1072 },
1073 {
1074 .name = "wm831x-on",
1075 .num_resources = ARRAY_SIZE(wm831x_on_resources),
1076 .resources = wm831x_on_resources,
1077 },
1078 {
1079 .name = "wm831x-power",
1080 .num_resources = ARRAY_SIZE(wm831x_power_resources),
1081 .resources = wm831x_power_resources,
1082 },
1083 {
1084 .name = "wm831x-rtc",
1085 .num_resources = ARRAY_SIZE(wm831x_rtc_resources),
1086 .resources = wm831x_rtc_resources,
1087 },
1088 {
1089 .name = "wm831x-status",
1090 .id = 1,
1091 .num_resources = ARRAY_SIZE(wm831x_status1_resources),
1092 .resources = wm831x_status1_resources,
1093 },
1094 {
1095 .name = "wm831x-status",
1096 .id = 2,
1097 .num_resources = ARRAY_SIZE(wm831x_status2_resources),
1098 .resources = wm831x_status2_resources,
1099 },
1100 {
1101 .name = "wm831x-touch",
1102 .num_resources = ARRAY_SIZE(wm831x_touch_resources),
1103 .resources = wm831x_touch_resources,
1104 },
1105 {
1106 .name = "wm831x-watchdog",
1107 .num_resources = ARRAY_SIZE(wm831x_wdt_resources),
1108 .resources = wm831x_wdt_resources,
1109 },
1110};
1111
1112static struct mfd_cell wm8312_devs[] = {
1113 {
Mark Brownc26964e2009-10-01 15:41:06 +01001114 .name = "wm831x-backup",
1115 },
1116 {
Mark Brownd2bedfe2009-07-27 14:45:52 +01001117 .name = "wm831x-buckv",
1118 .id = 1,
1119 .num_resources = ARRAY_SIZE(wm831x_dcdc1_resources),
1120 .resources = wm831x_dcdc1_resources,
1121 },
1122 {
1123 .name = "wm831x-buckv",
1124 .id = 2,
1125 .num_resources = ARRAY_SIZE(wm831x_dcdc2_resources),
1126 .resources = wm831x_dcdc2_resources,
1127 },
1128 {
1129 .name = "wm831x-buckp",
1130 .id = 3,
1131 .num_resources = ARRAY_SIZE(wm831x_dcdc3_resources),
1132 .resources = wm831x_dcdc3_resources,
1133 },
1134 {
1135 .name = "wm831x-boostp",
1136 .id = 4,
1137 .num_resources = ARRAY_SIZE(wm831x_dcdc4_resources),
1138 .resources = wm831x_dcdc4_resources,
1139 },
1140 {
1141 .name = "wm831x-epe",
1142 .id = 1,
1143 },
1144 {
1145 .name = "wm831x-epe",
1146 .id = 2,
1147 },
1148 {
1149 .name = "wm831x-gpio",
1150 .num_resources = ARRAY_SIZE(wm831x_gpio_resources),
1151 .resources = wm831x_gpio_resources,
1152 },
1153 {
1154 .name = "wm831x-hwmon",
1155 },
1156 {
1157 .name = "wm831x-isink",
1158 .id = 1,
1159 .num_resources = ARRAY_SIZE(wm831x_isink1_resources),
1160 .resources = wm831x_isink1_resources,
1161 },
1162 {
1163 .name = "wm831x-isink",
1164 .id = 2,
1165 .num_resources = ARRAY_SIZE(wm831x_isink2_resources),
1166 .resources = wm831x_isink2_resources,
1167 },
1168 {
1169 .name = "wm831x-ldo",
1170 .id = 1,
1171 .num_resources = ARRAY_SIZE(wm831x_ldo1_resources),
1172 .resources = wm831x_ldo1_resources,
1173 },
1174 {
1175 .name = "wm831x-ldo",
1176 .id = 2,
1177 .num_resources = ARRAY_SIZE(wm831x_ldo2_resources),
1178 .resources = wm831x_ldo2_resources,
1179 },
1180 {
1181 .name = "wm831x-ldo",
1182 .id = 3,
1183 .num_resources = ARRAY_SIZE(wm831x_ldo3_resources),
1184 .resources = wm831x_ldo3_resources,
1185 },
1186 {
1187 .name = "wm831x-ldo",
1188 .id = 4,
1189 .num_resources = ARRAY_SIZE(wm831x_ldo4_resources),
1190 .resources = wm831x_ldo4_resources,
1191 },
1192 {
1193 .name = "wm831x-ldo",
1194 .id = 5,
1195 .num_resources = ARRAY_SIZE(wm831x_ldo5_resources),
1196 .resources = wm831x_ldo5_resources,
1197 },
1198 {
1199 .name = "wm831x-ldo",
1200 .id = 6,
1201 .num_resources = ARRAY_SIZE(wm831x_ldo6_resources),
1202 .resources = wm831x_ldo6_resources,
1203 },
1204 {
1205 .name = "wm831x-aldo",
1206 .id = 7,
1207 .num_resources = ARRAY_SIZE(wm831x_ldo7_resources),
1208 .resources = wm831x_ldo7_resources,
1209 },
1210 {
1211 .name = "wm831x-aldo",
1212 .id = 8,
1213 .num_resources = ARRAY_SIZE(wm831x_ldo8_resources),
1214 .resources = wm831x_ldo8_resources,
1215 },
1216 {
1217 .name = "wm831x-aldo",
1218 .id = 9,
1219 .num_resources = ARRAY_SIZE(wm831x_ldo9_resources),
1220 .resources = wm831x_ldo9_resources,
1221 },
1222 {
1223 .name = "wm831x-aldo",
1224 .id = 10,
1225 .num_resources = ARRAY_SIZE(wm831x_ldo10_resources),
1226 .resources = wm831x_ldo10_resources,
1227 },
1228 {
1229 .name = "wm831x-alive-ldo",
1230 .id = 11,
1231 .num_resources = ARRAY_SIZE(wm831x_ldo11_resources),
1232 .resources = wm831x_ldo11_resources,
1233 },
1234 {
1235 .name = "wm831x-on",
1236 .num_resources = ARRAY_SIZE(wm831x_on_resources),
1237 .resources = wm831x_on_resources,
1238 },
1239 {
1240 .name = "wm831x-power",
1241 .num_resources = ARRAY_SIZE(wm831x_power_resources),
1242 .resources = wm831x_power_resources,
1243 },
1244 {
1245 .name = "wm831x-rtc",
1246 .num_resources = ARRAY_SIZE(wm831x_rtc_resources),
1247 .resources = wm831x_rtc_resources,
1248 },
1249 {
1250 .name = "wm831x-status",
1251 .id = 1,
1252 .num_resources = ARRAY_SIZE(wm831x_status1_resources),
1253 .resources = wm831x_status1_resources,
1254 },
1255 {
1256 .name = "wm831x-status",
1257 .id = 2,
1258 .num_resources = ARRAY_SIZE(wm831x_status2_resources),
1259 .resources = wm831x_status2_resources,
1260 },
1261 {
1262 .name = "wm831x-touch",
1263 .num_resources = ARRAY_SIZE(wm831x_touch_resources),
1264 .resources = wm831x_touch_resources,
1265 },
1266 {
1267 .name = "wm831x-watchdog",
1268 .num_resources = ARRAY_SIZE(wm831x_wdt_resources),
1269 .resources = wm831x_wdt_resources,
1270 },
1271};
1272
Mark Brownd4e0a892009-10-01 15:41:07 +01001273static struct mfd_cell wm8320_devs[] = {
1274 {
1275 .name = "wm831x-backup",
1276 },
1277 {
1278 .name = "wm831x-buckv",
1279 .id = 1,
1280 .num_resources = ARRAY_SIZE(wm831x_dcdc1_resources),
1281 .resources = wm831x_dcdc1_resources,
1282 },
1283 {
1284 .name = "wm831x-buckv",
1285 .id = 2,
1286 .num_resources = ARRAY_SIZE(wm831x_dcdc2_resources),
1287 .resources = wm831x_dcdc2_resources,
1288 },
1289 {
1290 .name = "wm831x-buckp",
1291 .id = 3,
1292 .num_resources = ARRAY_SIZE(wm831x_dcdc3_resources),
1293 .resources = wm831x_dcdc3_resources,
1294 },
1295 {
1296 .name = "wm831x-buckp",
1297 .id = 4,
1298 .num_resources = ARRAY_SIZE(wm8320_dcdc4_buck_resources),
1299 .resources = wm8320_dcdc4_buck_resources,
1300 },
1301 {
1302 .name = "wm831x-gpio",
1303 .num_resources = ARRAY_SIZE(wm831x_gpio_resources),
1304 .resources = wm831x_gpio_resources,
1305 },
1306 {
1307 .name = "wm831x-hwmon",
1308 },
1309 {
1310 .name = "wm831x-ldo",
1311 .id = 1,
1312 .num_resources = ARRAY_SIZE(wm831x_ldo1_resources),
1313 .resources = wm831x_ldo1_resources,
1314 },
1315 {
1316 .name = "wm831x-ldo",
1317 .id = 2,
1318 .num_resources = ARRAY_SIZE(wm831x_ldo2_resources),
1319 .resources = wm831x_ldo2_resources,
1320 },
1321 {
1322 .name = "wm831x-ldo",
1323 .id = 3,
1324 .num_resources = ARRAY_SIZE(wm831x_ldo3_resources),
1325 .resources = wm831x_ldo3_resources,
1326 },
1327 {
1328 .name = "wm831x-ldo",
1329 .id = 4,
1330 .num_resources = ARRAY_SIZE(wm831x_ldo4_resources),
1331 .resources = wm831x_ldo4_resources,
1332 },
1333 {
1334 .name = "wm831x-ldo",
1335 .id = 5,
1336 .num_resources = ARRAY_SIZE(wm831x_ldo5_resources),
1337 .resources = wm831x_ldo5_resources,
1338 },
1339 {
1340 .name = "wm831x-ldo",
1341 .id = 6,
1342 .num_resources = ARRAY_SIZE(wm831x_ldo6_resources),
1343 .resources = wm831x_ldo6_resources,
1344 },
1345 {
1346 .name = "wm831x-aldo",
1347 .id = 7,
1348 .num_resources = ARRAY_SIZE(wm831x_ldo7_resources),
1349 .resources = wm831x_ldo7_resources,
1350 },
1351 {
1352 .name = "wm831x-aldo",
1353 .id = 8,
1354 .num_resources = ARRAY_SIZE(wm831x_ldo8_resources),
1355 .resources = wm831x_ldo8_resources,
1356 },
1357 {
1358 .name = "wm831x-aldo",
1359 .id = 9,
1360 .num_resources = ARRAY_SIZE(wm831x_ldo9_resources),
1361 .resources = wm831x_ldo9_resources,
1362 },
1363 {
1364 .name = "wm831x-aldo",
1365 .id = 10,
1366 .num_resources = ARRAY_SIZE(wm831x_ldo10_resources),
1367 .resources = wm831x_ldo10_resources,
1368 },
1369 {
1370 .name = "wm831x-alive-ldo",
1371 .id = 11,
1372 .num_resources = ARRAY_SIZE(wm831x_ldo11_resources),
1373 .resources = wm831x_ldo11_resources,
1374 },
1375 {
1376 .name = "wm831x-on",
1377 .num_resources = ARRAY_SIZE(wm831x_on_resources),
1378 .resources = wm831x_on_resources,
1379 },
1380 {
1381 .name = "wm831x-rtc",
1382 .num_resources = ARRAY_SIZE(wm831x_rtc_resources),
1383 .resources = wm831x_rtc_resources,
1384 },
1385 {
1386 .name = "wm831x-status",
1387 .id = 1,
1388 .num_resources = ARRAY_SIZE(wm831x_status1_resources),
1389 .resources = wm831x_status1_resources,
1390 },
1391 {
1392 .name = "wm831x-status",
1393 .id = 2,
1394 .num_resources = ARRAY_SIZE(wm831x_status2_resources),
1395 .resources = wm831x_status2_resources,
1396 },
1397 {
1398 .name = "wm831x-watchdog",
1399 .num_resources = ARRAY_SIZE(wm831x_wdt_resources),
1400 .resources = wm831x_wdt_resources,
1401 },
1402};
1403
Mark Brown63aed852009-07-27 14:45:55 +01001404static struct mfd_cell backlight_devs[] = {
1405 {
1406 .name = "wm831x-backlight",
1407 },
1408};
1409
Mark Brownd2bedfe2009-07-27 14:45:52 +01001410/*
1411 * Instantiate the generic non-control parts of the device.
1412 */
1413static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
1414{
1415 struct wm831x_pdata *pdata = wm831x->dev->platform_data;
1416 int rev;
1417 enum wm831x_parent parent;
1418 int ret;
1419
1420 mutex_init(&wm831x->io_lock);
1421 mutex_init(&wm831x->key_lock);
Mark Brown7e9f9fd2009-07-27 14:45:54 +01001422 mutex_init(&wm831x->auxadc_lock);
Mark Brown473fe732010-02-23 11:08:06 +00001423 init_completion(&wm831x->auxadc_done);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001424 dev_set_drvdata(wm831x->dev, wm831x);
1425
1426 ret = wm831x_reg_read(wm831x, WM831X_PARENT_ID);
1427 if (ret < 0) {
1428 dev_err(wm831x->dev, "Failed to read parent ID: %d\n", ret);
1429 goto err;
1430 }
1431 if (ret != 0x6204) {
1432 dev_err(wm831x->dev, "Device is not a WM831x: ID %x\n", ret);
1433 ret = -EINVAL;
1434 goto err;
1435 }
1436
1437 ret = wm831x_reg_read(wm831x, WM831X_REVISION);
1438 if (ret < 0) {
1439 dev_err(wm831x->dev, "Failed to read revision: %d\n", ret);
1440 goto err;
1441 }
1442 rev = (ret & WM831X_PARENT_REV_MASK) >> WM831X_PARENT_REV_SHIFT;
1443
1444 ret = wm831x_reg_read(wm831x, WM831X_RESET_ID);
1445 if (ret < 0) {
1446 dev_err(wm831x->dev, "Failed to read device ID: %d\n", ret);
1447 goto err;
1448 }
1449
Mark Brown894362f2009-10-01 15:41:04 +01001450 /* Some engineering samples do not have the ID set, rely on
1451 * the device being registered correctly.
1452 */
1453 if (ret == 0) {
1454 dev_info(wm831x->dev, "Device is an engineering sample\n");
1455 ret = id;
1456 }
1457
Mark Brownd2bedfe2009-07-27 14:45:52 +01001458 switch (ret) {
Mark Brown894362f2009-10-01 15:41:04 +01001459 case WM8310:
Mark Brownd2bedfe2009-07-27 14:45:52 +01001460 parent = WM8310;
Mark Brown6f2ecaa2009-10-01 15:41:05 +01001461 wm831x->num_gpio = 16;
Mark Brownf92e8f82010-02-17 18:45:25 +00001462 if (rev > 0) {
1463 wm831x->has_gpio_ena = 1;
1464 wm831x->has_cs_sts = 1;
1465 }
1466
Mark Brown894362f2009-10-01 15:41:04 +01001467 dev_info(wm831x->dev, "WM8310 revision %c\n", 'A' + rev);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001468 break;
1469
Mark Brown894362f2009-10-01 15:41:04 +01001470 case WM8311:
Mark Brownd2bedfe2009-07-27 14:45:52 +01001471 parent = WM8311;
Mark Brown6f2ecaa2009-10-01 15:41:05 +01001472 wm831x->num_gpio = 16;
Mark Brownf92e8f82010-02-17 18:45:25 +00001473 if (rev > 0) {
1474 wm831x->has_gpio_ena = 1;
1475 wm831x->has_cs_sts = 1;
1476 }
1477
Mark Brown894362f2009-10-01 15:41:04 +01001478 dev_info(wm831x->dev, "WM8311 revision %c\n", 'A' + rev);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001479 break;
1480
Mark Brown894362f2009-10-01 15:41:04 +01001481 case WM8312:
Mark Brownd2bedfe2009-07-27 14:45:52 +01001482 parent = WM8312;
Mark Brown6f2ecaa2009-10-01 15:41:05 +01001483 wm831x->num_gpio = 16;
Mark Brownf92e8f82010-02-17 18:45:25 +00001484 if (rev > 0) {
1485 wm831x->has_gpio_ena = 1;
1486 wm831x->has_cs_sts = 1;
1487 }
1488
Mark Brown894362f2009-10-01 15:41:04 +01001489 dev_info(wm831x->dev, "WM8312 revision %c\n", 'A' + rev);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001490 break;
1491
Mark Brownd4e0a892009-10-01 15:41:07 +01001492 case WM8320:
1493 parent = WM8320;
1494 wm831x->num_gpio = 12;
1495 dev_info(wm831x->dev, "WM8320 revision %c\n", 'A' + rev);
1496 break;
1497
Mark Brownd2bedfe2009-07-27 14:45:52 +01001498 default:
1499 dev_err(wm831x->dev, "Unknown WM831x device %04x\n", ret);
1500 ret = -EINVAL;
1501 goto err;
1502 }
1503
1504 /* This will need revisiting in future but is OK for all
1505 * current parts.
1506 */
1507 if (parent != id)
Mark Brown894362f2009-10-01 15:41:04 +01001508 dev_warn(wm831x->dev, "Device was registered as a WM%lx\n",
Mark Brownd2bedfe2009-07-27 14:45:52 +01001509 id);
1510
1511 /* Bootstrap the user key */
1512 ret = wm831x_reg_read(wm831x, WM831X_SECURITY_KEY);
1513 if (ret < 0) {
1514 dev_err(wm831x->dev, "Failed to read security key: %d\n", ret);
1515 goto err;
1516 }
1517 if (ret != 0) {
1518 dev_warn(wm831x->dev, "Security key had non-zero value %x\n",
1519 ret);
1520 wm831x_reg_write(wm831x, WM831X_SECURITY_KEY, 0);
1521 }
1522 wm831x->locked = 1;
1523
1524 if (pdata && pdata->pre_init) {
1525 ret = pdata->pre_init(wm831x);
1526 if (ret != 0) {
1527 dev_err(wm831x->dev, "pre_init() failed: %d\n", ret);
1528 goto err;
1529 }
1530 }
1531
Mark Brown7d4d0a32009-07-27 14:45:53 +01001532 ret = wm831x_irq_init(wm831x, irq);
1533 if (ret != 0)
1534 goto err;
1535
Mark Brown473fe732010-02-23 11:08:06 +00001536 if (wm831x->irq_base) {
1537 ret = request_threaded_irq(wm831x->irq_base +
1538 WM831X_IRQ_AUXADC_DATA,
1539 NULL, wm831x_auxadc_irq, 0,
1540 "auxadc", wm831x);
1541 if (ret < 0)
1542 dev_err(wm831x->dev, "AUXADC IRQ request failed: %d\n",
1543 ret);
1544 }
1545
Mark Brownd2bedfe2009-07-27 14:45:52 +01001546 /* The core device is up, instantiate the subdevices. */
1547 switch (parent) {
1548 case WM8310:
1549 ret = mfd_add_devices(wm831x->dev, -1,
1550 wm8310_devs, ARRAY_SIZE(wm8310_devs),
Mark Brown5fb4d382009-11-11 16:10:22 +00001551 NULL, wm831x->irq_base);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001552 break;
1553
1554 case WM8311:
1555 ret = mfd_add_devices(wm831x->dev, -1,
1556 wm8311_devs, ARRAY_SIZE(wm8311_devs),
Mark Brown5fb4d382009-11-11 16:10:22 +00001557 NULL, wm831x->irq_base);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001558 break;
1559
1560 case WM8312:
1561 ret = mfd_add_devices(wm831x->dev, -1,
1562 wm8312_devs, ARRAY_SIZE(wm8312_devs),
Mark Brown5fb4d382009-11-11 16:10:22 +00001563 NULL, wm831x->irq_base);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001564 break;
1565
Mark Brownd4e0a892009-10-01 15:41:07 +01001566 case WM8320:
1567 ret = mfd_add_devices(wm831x->dev, -1,
1568 wm8320_devs, ARRAY_SIZE(wm8320_devs),
1569 NULL, 0);
1570 break;
1571
Mark Brownd2bedfe2009-07-27 14:45:52 +01001572 default:
1573 /* If this happens the bus probe function is buggy */
1574 BUG();
1575 }
1576
1577 if (ret != 0) {
1578 dev_err(wm831x->dev, "Failed to add children\n");
Mark Brown7d4d0a32009-07-27 14:45:53 +01001579 goto err_irq;
Mark Brownd2bedfe2009-07-27 14:45:52 +01001580 }
1581
Mark Brown63aed852009-07-27 14:45:55 +01001582 if (pdata && pdata->backlight) {
1583 /* Treat errors as non-critical */
1584 ret = mfd_add_devices(wm831x->dev, -1, backlight_devs,
Mark Brown5fb4d382009-11-11 16:10:22 +00001585 ARRAY_SIZE(backlight_devs), NULL,
1586 wm831x->irq_base);
Mark Brown63aed852009-07-27 14:45:55 +01001587 if (ret < 0)
1588 dev_err(wm831x->dev, "Failed to add backlight: %d\n",
1589 ret);
1590 }
1591
Mark Brown6704e512009-07-27 14:45:56 +01001592 wm831x_otp_init(wm831x);
1593
Mark Brownd2bedfe2009-07-27 14:45:52 +01001594 if (pdata && pdata->post_init) {
1595 ret = pdata->post_init(wm831x);
1596 if (ret != 0) {
1597 dev_err(wm831x->dev, "post_init() failed: %d\n", ret);
Mark Brown7d4d0a32009-07-27 14:45:53 +01001598 goto err_irq;
Mark Brownd2bedfe2009-07-27 14:45:52 +01001599 }
1600 }
1601
1602 return 0;
1603
Mark Brown7d4d0a32009-07-27 14:45:53 +01001604err_irq:
1605 wm831x_irq_exit(wm831x);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001606err:
1607 mfd_remove_devices(wm831x->dev);
1608 kfree(wm831x);
1609 return ret;
1610}
1611
1612static void wm831x_device_exit(struct wm831x *wm831x)
1613{
Mark Brown6704e512009-07-27 14:45:56 +01001614 wm831x_otp_exit(wm831x);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001615 mfd_remove_devices(wm831x->dev);
Mark Brown473fe732010-02-23 11:08:06 +00001616 if (wm831x->irq_base)
1617 free_irq(wm831x->irq_base + WM831X_IRQ_AUXADC_DATA, wm831x);
Mark Brown7d4d0a32009-07-27 14:45:53 +01001618 wm831x_irq_exit(wm831x);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001619 kfree(wm831x);
1620}
1621
1622static int wm831x_i2c_read_device(struct wm831x *wm831x, unsigned short reg,
1623 int bytes, void *dest)
1624{
1625 struct i2c_client *i2c = wm831x->control_data;
1626 int ret;
1627 u16 r = cpu_to_be16(reg);
1628
1629 ret = i2c_master_send(i2c, (unsigned char *)&r, 2);
1630 if (ret < 0)
1631 return ret;
1632 if (ret != 2)
1633 return -EIO;
1634
1635 ret = i2c_master_recv(i2c, dest, bytes);
1636 if (ret < 0)
1637 return ret;
1638 if (ret != bytes)
1639 return -EIO;
1640 return 0;
1641}
1642
1643/* Currently we allocate the write buffer on the stack; this is OK for
1644 * small writes - if we need to do large writes this will need to be
1645 * revised.
1646 */
1647static int wm831x_i2c_write_device(struct wm831x *wm831x, unsigned short reg,
1648 int bytes, void *src)
1649{
1650 struct i2c_client *i2c = wm831x->control_data;
1651 unsigned char msg[bytes + 2];
1652 int ret;
1653
1654 reg = cpu_to_be16(reg);
1655 memcpy(&msg[0], &reg, 2);
1656 memcpy(&msg[2], src, bytes);
1657
1658 ret = i2c_master_send(i2c, msg, bytes + 2);
1659 if (ret < 0)
1660 return ret;
1661 if (ret < bytes + 2)
1662 return -EIO;
1663
1664 return 0;
1665}
1666
1667static int wm831x_i2c_probe(struct i2c_client *i2c,
1668 const struct i2c_device_id *id)
1669{
1670 struct wm831x *wm831x;
1671
1672 wm831x = kzalloc(sizeof(struct wm831x), GFP_KERNEL);
1673 if (wm831x == NULL) {
1674 kfree(i2c);
1675 return -ENOMEM;
1676 }
1677
1678 i2c_set_clientdata(i2c, wm831x);
1679 wm831x->dev = &i2c->dev;
1680 wm831x->control_data = i2c;
1681 wm831x->read_dev = wm831x_i2c_read_device;
1682 wm831x->write_dev = wm831x_i2c_write_device;
1683
1684 return wm831x_device_init(wm831x, id->driver_data, i2c->irq);
1685}
1686
1687static int wm831x_i2c_remove(struct i2c_client *i2c)
1688{
1689 struct wm831x *wm831x = i2c_get_clientdata(i2c);
1690
1691 wm831x_device_exit(wm831x);
1692
1693 return 0;
1694}
1695
1696static const struct i2c_device_id wm831x_i2c_id[] = {
1697 { "wm8310", WM8310 },
1698 { "wm8311", WM8311 },
1699 { "wm8312", WM8312 },
Mark Brownd4e0a892009-10-01 15:41:07 +01001700 { "wm8320", WM8320 },
Mark Brownd2bedfe2009-07-27 14:45:52 +01001701 { }
1702};
1703MODULE_DEVICE_TABLE(i2c, wm831x_i2c_id);
1704
1705
1706static struct i2c_driver wm831x_i2c_driver = {
1707 .driver = {
1708 .name = "wm831x",
1709 .owner = THIS_MODULE,
1710 },
1711 .probe = wm831x_i2c_probe,
1712 .remove = wm831x_i2c_remove,
1713 .id_table = wm831x_i2c_id,
1714};
1715
1716static int __init wm831x_i2c_init(void)
1717{
1718 int ret;
1719
1720 ret = i2c_add_driver(&wm831x_i2c_driver);
1721 if (ret != 0)
1722 pr_err("Failed to register wm831x I2C driver: %d\n", ret);
1723
1724 return ret;
1725}
1726subsys_initcall(wm831x_i2c_init);
1727
1728static void __exit wm831x_i2c_exit(void)
1729{
1730 i2c_del_driver(&wm831x_i2c_driver);
1731}
1732module_exit(wm831x_i2c_exit);
1733
1734MODULE_DESCRIPTION("I2C support for the WM831X AudioPlus PMIC");
1735MODULE_LICENSE("GPL");
1736MODULE_AUTHOR("Mark Brown");