blob: 163029f0618579ddd11b1ccf0ced06e6b33754d9 [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 {
812 .name = "wm831x-buckv",
813 .id = 1,
814 .num_resources = ARRAY_SIZE(wm831x_dcdc1_resources),
815 .resources = wm831x_dcdc1_resources,
816 },
817 {
818 .name = "wm831x-buckv",
819 .id = 2,
820 .num_resources = ARRAY_SIZE(wm831x_dcdc2_resources),
821 .resources = wm831x_dcdc2_resources,
822 },
823 {
824 .name = "wm831x-buckp",
825 .id = 3,
826 .num_resources = ARRAY_SIZE(wm831x_dcdc3_resources),
827 .resources = wm831x_dcdc3_resources,
828 },
829 {
830 .name = "wm831x-boostp",
831 .id = 4,
832 .num_resources = ARRAY_SIZE(wm831x_dcdc4_resources),
833 .resources = wm831x_dcdc4_resources,
834 },
835 {
836 .name = "wm831x-epe",
837 .id = 1,
838 },
839 {
840 .name = "wm831x-epe",
841 .id = 2,
842 },
843 {
844 .name = "wm831x-gpio",
845 .num_resources = ARRAY_SIZE(wm831x_gpio_resources),
846 .resources = wm831x_gpio_resources,
847 },
848 {
849 .name = "wm831x-hwmon",
850 },
851 {
852 .name = "wm831x-isink",
853 .id = 1,
854 .num_resources = ARRAY_SIZE(wm831x_isink1_resources),
855 .resources = wm831x_isink1_resources,
856 },
857 {
858 .name = "wm831x-isink",
859 .id = 2,
860 .num_resources = ARRAY_SIZE(wm831x_isink2_resources),
861 .resources = wm831x_isink2_resources,
862 },
863 {
864 .name = "wm831x-ldo",
865 .id = 1,
866 .num_resources = ARRAY_SIZE(wm831x_ldo1_resources),
867 .resources = wm831x_ldo1_resources,
868 },
869 {
870 .name = "wm831x-ldo",
871 .id = 2,
872 .num_resources = ARRAY_SIZE(wm831x_ldo2_resources),
873 .resources = wm831x_ldo2_resources,
874 },
875 {
876 .name = "wm831x-ldo",
877 .id = 3,
878 .num_resources = ARRAY_SIZE(wm831x_ldo3_resources),
879 .resources = wm831x_ldo3_resources,
880 },
881 {
882 .name = "wm831x-ldo",
883 .id = 4,
884 .num_resources = ARRAY_SIZE(wm831x_ldo4_resources),
885 .resources = wm831x_ldo4_resources,
886 },
887 {
888 .name = "wm831x-ldo",
889 .id = 5,
890 .num_resources = ARRAY_SIZE(wm831x_ldo5_resources),
891 .resources = wm831x_ldo5_resources,
892 },
893 {
894 .name = "wm831x-ldo",
895 .id = 6,
896 .num_resources = ARRAY_SIZE(wm831x_ldo6_resources),
897 .resources = wm831x_ldo6_resources,
898 },
899 {
900 .name = "wm831x-aldo",
901 .id = 7,
902 .num_resources = ARRAY_SIZE(wm831x_ldo7_resources),
903 .resources = wm831x_ldo7_resources,
904 },
905 {
906 .name = "wm831x-aldo",
907 .id = 8,
908 .num_resources = ARRAY_SIZE(wm831x_ldo8_resources),
909 .resources = wm831x_ldo8_resources,
910 },
911 {
912 .name = "wm831x-aldo",
913 .id = 9,
914 .num_resources = ARRAY_SIZE(wm831x_ldo9_resources),
915 .resources = wm831x_ldo9_resources,
916 },
917 {
918 .name = "wm831x-aldo",
919 .id = 10,
920 .num_resources = ARRAY_SIZE(wm831x_ldo10_resources),
921 .resources = wm831x_ldo10_resources,
922 },
923 {
924 .name = "wm831x-alive-ldo",
925 .id = 11,
926 .num_resources = ARRAY_SIZE(wm831x_ldo11_resources),
927 .resources = wm831x_ldo11_resources,
928 },
929 {
930 .name = "wm831x-on",
931 .num_resources = ARRAY_SIZE(wm831x_on_resources),
932 .resources = wm831x_on_resources,
933 },
934 {
935 .name = "wm831x-power",
936 .num_resources = ARRAY_SIZE(wm831x_power_resources),
937 .resources = wm831x_power_resources,
938 },
939 {
940 .name = "wm831x-rtc",
941 .num_resources = ARRAY_SIZE(wm831x_rtc_resources),
942 .resources = wm831x_rtc_resources,
943 },
944 {
945 .name = "wm831x-status",
946 .id = 1,
947 .num_resources = ARRAY_SIZE(wm831x_status1_resources),
948 .resources = wm831x_status1_resources,
949 },
950 {
951 .name = "wm831x-status",
952 .id = 2,
953 .num_resources = ARRAY_SIZE(wm831x_status2_resources),
954 .resources = wm831x_status2_resources,
955 },
956 {
957 .name = "wm831x-watchdog",
958 .num_resources = ARRAY_SIZE(wm831x_wdt_resources),
959 .resources = wm831x_wdt_resources,
960 },
961};
962
963static struct mfd_cell wm8311_devs[] = {
964 {
965 .name = "wm831x-buckv",
966 .id = 1,
967 .num_resources = ARRAY_SIZE(wm831x_dcdc1_resources),
968 .resources = wm831x_dcdc1_resources,
969 },
970 {
971 .name = "wm831x-buckv",
972 .id = 2,
973 .num_resources = ARRAY_SIZE(wm831x_dcdc2_resources),
974 .resources = wm831x_dcdc2_resources,
975 },
976 {
977 .name = "wm831x-buckp",
978 .id = 3,
979 .num_resources = ARRAY_SIZE(wm831x_dcdc3_resources),
980 .resources = wm831x_dcdc3_resources,
981 },
982 {
983 .name = "wm831x-boostp",
984 .id = 4,
985 .num_resources = ARRAY_SIZE(wm831x_dcdc4_resources),
986 .resources = wm831x_dcdc4_resources,
987 },
988 {
989 .name = "wm831x-epe",
990 .id = 1,
991 },
992 {
993 .name = "wm831x-epe",
994 .id = 2,
995 },
996 {
997 .name = "wm831x-gpio",
998 .num_resources = ARRAY_SIZE(wm831x_gpio_resources),
999 .resources = wm831x_gpio_resources,
1000 },
1001 {
1002 .name = "wm831x-hwmon",
1003 },
1004 {
1005 .name = "wm831x-isink",
1006 .id = 1,
1007 .num_resources = ARRAY_SIZE(wm831x_isink1_resources),
1008 .resources = wm831x_isink1_resources,
1009 },
1010 {
1011 .name = "wm831x-isink",
1012 .id = 2,
1013 .num_resources = ARRAY_SIZE(wm831x_isink2_resources),
1014 .resources = wm831x_isink2_resources,
1015 },
1016 {
1017 .name = "wm831x-ldo",
1018 .id = 1,
1019 .num_resources = ARRAY_SIZE(wm831x_ldo1_resources),
1020 .resources = wm831x_ldo1_resources,
1021 },
1022 {
1023 .name = "wm831x-ldo",
1024 .id = 2,
1025 .num_resources = ARRAY_SIZE(wm831x_ldo2_resources),
1026 .resources = wm831x_ldo2_resources,
1027 },
1028 {
1029 .name = "wm831x-ldo",
1030 .id = 3,
1031 .num_resources = ARRAY_SIZE(wm831x_ldo3_resources),
1032 .resources = wm831x_ldo3_resources,
1033 },
1034 {
1035 .name = "wm831x-ldo",
1036 .id = 4,
1037 .num_resources = ARRAY_SIZE(wm831x_ldo4_resources),
1038 .resources = wm831x_ldo4_resources,
1039 },
1040 {
1041 .name = "wm831x-ldo",
1042 .id = 5,
1043 .num_resources = ARRAY_SIZE(wm831x_ldo5_resources),
1044 .resources = wm831x_ldo5_resources,
1045 },
1046 {
1047 .name = "wm831x-aldo",
1048 .id = 7,
1049 .num_resources = ARRAY_SIZE(wm831x_ldo7_resources),
1050 .resources = wm831x_ldo7_resources,
1051 },
1052 {
1053 .name = "wm831x-alive-ldo",
1054 .id = 11,
1055 .num_resources = ARRAY_SIZE(wm831x_ldo11_resources),
1056 .resources = wm831x_ldo11_resources,
1057 },
1058 {
1059 .name = "wm831x-on",
1060 .num_resources = ARRAY_SIZE(wm831x_on_resources),
1061 .resources = wm831x_on_resources,
1062 },
1063 {
1064 .name = "wm831x-power",
1065 .num_resources = ARRAY_SIZE(wm831x_power_resources),
1066 .resources = wm831x_power_resources,
1067 },
1068 {
1069 .name = "wm831x-rtc",
1070 .num_resources = ARRAY_SIZE(wm831x_rtc_resources),
1071 .resources = wm831x_rtc_resources,
1072 },
1073 {
1074 .name = "wm831x-status",
1075 .id = 1,
1076 .num_resources = ARRAY_SIZE(wm831x_status1_resources),
1077 .resources = wm831x_status1_resources,
1078 },
1079 {
1080 .name = "wm831x-status",
1081 .id = 2,
1082 .num_resources = ARRAY_SIZE(wm831x_status2_resources),
1083 .resources = wm831x_status2_resources,
1084 },
1085 {
1086 .name = "wm831x-touch",
1087 .num_resources = ARRAY_SIZE(wm831x_touch_resources),
1088 .resources = wm831x_touch_resources,
1089 },
1090 {
1091 .name = "wm831x-watchdog",
1092 .num_resources = ARRAY_SIZE(wm831x_wdt_resources),
1093 .resources = wm831x_wdt_resources,
1094 },
1095};
1096
1097static struct mfd_cell wm8312_devs[] = {
1098 {
1099 .name = "wm831x-buckv",
1100 .id = 1,
1101 .num_resources = ARRAY_SIZE(wm831x_dcdc1_resources),
1102 .resources = wm831x_dcdc1_resources,
1103 },
1104 {
1105 .name = "wm831x-buckv",
1106 .id = 2,
1107 .num_resources = ARRAY_SIZE(wm831x_dcdc2_resources),
1108 .resources = wm831x_dcdc2_resources,
1109 },
1110 {
1111 .name = "wm831x-buckp",
1112 .id = 3,
1113 .num_resources = ARRAY_SIZE(wm831x_dcdc3_resources),
1114 .resources = wm831x_dcdc3_resources,
1115 },
1116 {
1117 .name = "wm831x-boostp",
1118 .id = 4,
1119 .num_resources = ARRAY_SIZE(wm831x_dcdc4_resources),
1120 .resources = wm831x_dcdc4_resources,
1121 },
1122 {
1123 .name = "wm831x-epe",
1124 .id = 1,
1125 },
1126 {
1127 .name = "wm831x-epe",
1128 .id = 2,
1129 },
1130 {
1131 .name = "wm831x-gpio",
1132 .num_resources = ARRAY_SIZE(wm831x_gpio_resources),
1133 .resources = wm831x_gpio_resources,
1134 },
1135 {
1136 .name = "wm831x-hwmon",
1137 },
1138 {
1139 .name = "wm831x-isink",
1140 .id = 1,
1141 .num_resources = ARRAY_SIZE(wm831x_isink1_resources),
1142 .resources = wm831x_isink1_resources,
1143 },
1144 {
1145 .name = "wm831x-isink",
1146 .id = 2,
1147 .num_resources = ARRAY_SIZE(wm831x_isink2_resources),
1148 .resources = wm831x_isink2_resources,
1149 },
1150 {
1151 .name = "wm831x-ldo",
1152 .id = 1,
1153 .num_resources = ARRAY_SIZE(wm831x_ldo1_resources),
1154 .resources = wm831x_ldo1_resources,
1155 },
1156 {
1157 .name = "wm831x-ldo",
1158 .id = 2,
1159 .num_resources = ARRAY_SIZE(wm831x_ldo2_resources),
1160 .resources = wm831x_ldo2_resources,
1161 },
1162 {
1163 .name = "wm831x-ldo",
1164 .id = 3,
1165 .num_resources = ARRAY_SIZE(wm831x_ldo3_resources),
1166 .resources = wm831x_ldo3_resources,
1167 },
1168 {
1169 .name = "wm831x-ldo",
1170 .id = 4,
1171 .num_resources = ARRAY_SIZE(wm831x_ldo4_resources),
1172 .resources = wm831x_ldo4_resources,
1173 },
1174 {
1175 .name = "wm831x-ldo",
1176 .id = 5,
1177 .num_resources = ARRAY_SIZE(wm831x_ldo5_resources),
1178 .resources = wm831x_ldo5_resources,
1179 },
1180 {
1181 .name = "wm831x-ldo",
1182 .id = 6,
1183 .num_resources = ARRAY_SIZE(wm831x_ldo6_resources),
1184 .resources = wm831x_ldo6_resources,
1185 },
1186 {
1187 .name = "wm831x-aldo",
1188 .id = 7,
1189 .num_resources = ARRAY_SIZE(wm831x_ldo7_resources),
1190 .resources = wm831x_ldo7_resources,
1191 },
1192 {
1193 .name = "wm831x-aldo",
1194 .id = 8,
1195 .num_resources = ARRAY_SIZE(wm831x_ldo8_resources),
1196 .resources = wm831x_ldo8_resources,
1197 },
1198 {
1199 .name = "wm831x-aldo",
1200 .id = 9,
1201 .num_resources = ARRAY_SIZE(wm831x_ldo9_resources),
1202 .resources = wm831x_ldo9_resources,
1203 },
1204 {
1205 .name = "wm831x-aldo",
1206 .id = 10,
1207 .num_resources = ARRAY_SIZE(wm831x_ldo10_resources),
1208 .resources = wm831x_ldo10_resources,
1209 },
1210 {
1211 .name = "wm831x-alive-ldo",
1212 .id = 11,
1213 .num_resources = ARRAY_SIZE(wm831x_ldo11_resources),
1214 .resources = wm831x_ldo11_resources,
1215 },
1216 {
1217 .name = "wm831x-on",
1218 .num_resources = ARRAY_SIZE(wm831x_on_resources),
1219 .resources = wm831x_on_resources,
1220 },
1221 {
1222 .name = "wm831x-power",
1223 .num_resources = ARRAY_SIZE(wm831x_power_resources),
1224 .resources = wm831x_power_resources,
1225 },
1226 {
1227 .name = "wm831x-rtc",
1228 .num_resources = ARRAY_SIZE(wm831x_rtc_resources),
1229 .resources = wm831x_rtc_resources,
1230 },
1231 {
1232 .name = "wm831x-status",
1233 .id = 1,
1234 .num_resources = ARRAY_SIZE(wm831x_status1_resources),
1235 .resources = wm831x_status1_resources,
1236 },
1237 {
1238 .name = "wm831x-status",
1239 .id = 2,
1240 .num_resources = ARRAY_SIZE(wm831x_status2_resources),
1241 .resources = wm831x_status2_resources,
1242 },
1243 {
1244 .name = "wm831x-touch",
1245 .num_resources = ARRAY_SIZE(wm831x_touch_resources),
1246 .resources = wm831x_touch_resources,
1247 },
1248 {
1249 .name = "wm831x-watchdog",
1250 .num_resources = ARRAY_SIZE(wm831x_wdt_resources),
1251 .resources = wm831x_wdt_resources,
1252 },
1253};
1254
Mark Brownd4e0a892009-10-01 15:41:07 +01001255static struct mfd_cell wm8320_devs[] = {
1256 {
1257 .name = "wm831x-backup",
1258 },
1259 {
1260 .name = "wm831x-buckv",
1261 .id = 1,
1262 .num_resources = ARRAY_SIZE(wm831x_dcdc1_resources),
1263 .resources = wm831x_dcdc1_resources,
1264 },
1265 {
1266 .name = "wm831x-buckv",
1267 .id = 2,
1268 .num_resources = ARRAY_SIZE(wm831x_dcdc2_resources),
1269 .resources = wm831x_dcdc2_resources,
1270 },
1271 {
1272 .name = "wm831x-buckp",
1273 .id = 3,
1274 .num_resources = ARRAY_SIZE(wm831x_dcdc3_resources),
1275 .resources = wm831x_dcdc3_resources,
1276 },
1277 {
1278 .name = "wm831x-buckp",
1279 .id = 4,
1280 .num_resources = ARRAY_SIZE(wm8320_dcdc4_buck_resources),
1281 .resources = wm8320_dcdc4_buck_resources,
1282 },
1283 {
1284 .name = "wm831x-gpio",
1285 .num_resources = ARRAY_SIZE(wm831x_gpio_resources),
1286 .resources = wm831x_gpio_resources,
1287 },
1288 {
1289 .name = "wm831x-hwmon",
1290 },
1291 {
1292 .name = "wm831x-ldo",
1293 .id = 1,
1294 .num_resources = ARRAY_SIZE(wm831x_ldo1_resources),
1295 .resources = wm831x_ldo1_resources,
1296 },
1297 {
1298 .name = "wm831x-ldo",
1299 .id = 2,
1300 .num_resources = ARRAY_SIZE(wm831x_ldo2_resources),
1301 .resources = wm831x_ldo2_resources,
1302 },
1303 {
1304 .name = "wm831x-ldo",
1305 .id = 3,
1306 .num_resources = ARRAY_SIZE(wm831x_ldo3_resources),
1307 .resources = wm831x_ldo3_resources,
1308 },
1309 {
1310 .name = "wm831x-ldo",
1311 .id = 4,
1312 .num_resources = ARRAY_SIZE(wm831x_ldo4_resources),
1313 .resources = wm831x_ldo4_resources,
1314 },
1315 {
1316 .name = "wm831x-ldo",
1317 .id = 5,
1318 .num_resources = ARRAY_SIZE(wm831x_ldo5_resources),
1319 .resources = wm831x_ldo5_resources,
1320 },
1321 {
1322 .name = "wm831x-ldo",
1323 .id = 6,
1324 .num_resources = ARRAY_SIZE(wm831x_ldo6_resources),
1325 .resources = wm831x_ldo6_resources,
1326 },
1327 {
1328 .name = "wm831x-aldo",
1329 .id = 7,
1330 .num_resources = ARRAY_SIZE(wm831x_ldo7_resources),
1331 .resources = wm831x_ldo7_resources,
1332 },
1333 {
1334 .name = "wm831x-aldo",
1335 .id = 8,
1336 .num_resources = ARRAY_SIZE(wm831x_ldo8_resources),
1337 .resources = wm831x_ldo8_resources,
1338 },
1339 {
1340 .name = "wm831x-aldo",
1341 .id = 9,
1342 .num_resources = ARRAY_SIZE(wm831x_ldo9_resources),
1343 .resources = wm831x_ldo9_resources,
1344 },
1345 {
1346 .name = "wm831x-aldo",
1347 .id = 10,
1348 .num_resources = ARRAY_SIZE(wm831x_ldo10_resources),
1349 .resources = wm831x_ldo10_resources,
1350 },
1351 {
1352 .name = "wm831x-alive-ldo",
1353 .id = 11,
1354 .num_resources = ARRAY_SIZE(wm831x_ldo11_resources),
1355 .resources = wm831x_ldo11_resources,
1356 },
1357 {
1358 .name = "wm831x-on",
1359 .num_resources = ARRAY_SIZE(wm831x_on_resources),
1360 .resources = wm831x_on_resources,
1361 },
1362 {
1363 .name = "wm831x-rtc",
1364 .num_resources = ARRAY_SIZE(wm831x_rtc_resources),
1365 .resources = wm831x_rtc_resources,
1366 },
1367 {
1368 .name = "wm831x-status",
1369 .id = 1,
1370 .num_resources = ARRAY_SIZE(wm831x_status1_resources),
1371 .resources = wm831x_status1_resources,
1372 },
1373 {
1374 .name = "wm831x-status",
1375 .id = 2,
1376 .num_resources = ARRAY_SIZE(wm831x_status2_resources),
1377 .resources = wm831x_status2_resources,
1378 },
1379 {
1380 .name = "wm831x-watchdog",
1381 .num_resources = ARRAY_SIZE(wm831x_wdt_resources),
1382 .resources = wm831x_wdt_resources,
1383 },
1384};
1385
Mark Brown63aed852009-07-27 14:45:55 +01001386static struct mfd_cell backlight_devs[] = {
1387 {
1388 .name = "wm831x-backlight",
1389 },
1390};
1391
Mark Brownd2bedfe2009-07-27 14:45:52 +01001392/*
1393 * Instantiate the generic non-control parts of the device.
1394 */
1395static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
1396{
1397 struct wm831x_pdata *pdata = wm831x->dev->platform_data;
1398 int rev;
1399 enum wm831x_parent parent;
1400 int ret;
1401
1402 mutex_init(&wm831x->io_lock);
1403 mutex_init(&wm831x->key_lock);
Mark Brown7e9f9fd2009-07-27 14:45:54 +01001404 mutex_init(&wm831x->auxadc_lock);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001405 dev_set_drvdata(wm831x->dev, wm831x);
1406
1407 ret = wm831x_reg_read(wm831x, WM831X_PARENT_ID);
1408 if (ret < 0) {
1409 dev_err(wm831x->dev, "Failed to read parent ID: %d\n", ret);
1410 goto err;
1411 }
1412 if (ret != 0x6204) {
1413 dev_err(wm831x->dev, "Device is not a WM831x: ID %x\n", ret);
1414 ret = -EINVAL;
1415 goto err;
1416 }
1417
1418 ret = wm831x_reg_read(wm831x, WM831X_REVISION);
1419 if (ret < 0) {
1420 dev_err(wm831x->dev, "Failed to read revision: %d\n", ret);
1421 goto err;
1422 }
1423 rev = (ret & WM831X_PARENT_REV_MASK) >> WM831X_PARENT_REV_SHIFT;
1424
1425 ret = wm831x_reg_read(wm831x, WM831X_RESET_ID);
1426 if (ret < 0) {
1427 dev_err(wm831x->dev, "Failed to read device ID: %d\n", ret);
1428 goto err;
1429 }
1430
Mark Brown894362f2009-10-01 15:41:04 +01001431 /* Some engineering samples do not have the ID set, rely on
1432 * the device being registered correctly.
1433 */
1434 if (ret == 0) {
1435 dev_info(wm831x->dev, "Device is an engineering sample\n");
1436 ret = id;
1437 }
1438
Mark Brownd2bedfe2009-07-27 14:45:52 +01001439 switch (ret) {
Mark Brown894362f2009-10-01 15:41:04 +01001440 case WM8310:
Mark Brownd2bedfe2009-07-27 14:45:52 +01001441 parent = WM8310;
Mark Brown6f2ecaa2009-10-01 15:41:05 +01001442 wm831x->num_gpio = 16;
Mark Brown894362f2009-10-01 15:41:04 +01001443 dev_info(wm831x->dev, "WM8310 revision %c\n", 'A' + rev);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001444 break;
1445
Mark Brown894362f2009-10-01 15:41:04 +01001446 case WM8311:
Mark Brownd2bedfe2009-07-27 14:45:52 +01001447 parent = WM8311;
Mark Brown6f2ecaa2009-10-01 15:41:05 +01001448 wm831x->num_gpio = 16;
Mark Brown894362f2009-10-01 15:41:04 +01001449 dev_info(wm831x->dev, "WM8311 revision %c\n", 'A' + rev);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001450 break;
1451
Mark Brown894362f2009-10-01 15:41:04 +01001452 case WM8312:
Mark Brownd2bedfe2009-07-27 14:45:52 +01001453 parent = WM8312;
Mark Brown6f2ecaa2009-10-01 15:41:05 +01001454 wm831x->num_gpio = 16;
Mark Brown894362f2009-10-01 15:41:04 +01001455 dev_info(wm831x->dev, "WM8312 revision %c\n", 'A' + rev);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001456 break;
1457
Mark Brownd4e0a892009-10-01 15:41:07 +01001458 case WM8320:
1459 parent = WM8320;
1460 wm831x->num_gpio = 12;
1461 dev_info(wm831x->dev, "WM8320 revision %c\n", 'A' + rev);
1462 break;
1463
Mark Brownd2bedfe2009-07-27 14:45:52 +01001464 default:
1465 dev_err(wm831x->dev, "Unknown WM831x device %04x\n", ret);
1466 ret = -EINVAL;
1467 goto err;
1468 }
1469
1470 /* This will need revisiting in future but is OK for all
1471 * current parts.
1472 */
1473 if (parent != id)
Mark Brown894362f2009-10-01 15:41:04 +01001474 dev_warn(wm831x->dev, "Device was registered as a WM%lx\n",
Mark Brownd2bedfe2009-07-27 14:45:52 +01001475 id);
1476
1477 /* Bootstrap the user key */
1478 ret = wm831x_reg_read(wm831x, WM831X_SECURITY_KEY);
1479 if (ret < 0) {
1480 dev_err(wm831x->dev, "Failed to read security key: %d\n", ret);
1481 goto err;
1482 }
1483 if (ret != 0) {
1484 dev_warn(wm831x->dev, "Security key had non-zero value %x\n",
1485 ret);
1486 wm831x_reg_write(wm831x, WM831X_SECURITY_KEY, 0);
1487 }
1488 wm831x->locked = 1;
1489
1490 if (pdata && pdata->pre_init) {
1491 ret = pdata->pre_init(wm831x);
1492 if (ret != 0) {
1493 dev_err(wm831x->dev, "pre_init() failed: %d\n", ret);
1494 goto err;
1495 }
1496 }
1497
Mark Brown7d4d0a32009-07-27 14:45:53 +01001498 ret = wm831x_irq_init(wm831x, irq);
1499 if (ret != 0)
1500 goto err;
1501
Mark Brownd2bedfe2009-07-27 14:45:52 +01001502 /* The core device is up, instantiate the subdevices. */
1503 switch (parent) {
1504 case WM8310:
1505 ret = mfd_add_devices(wm831x->dev, -1,
1506 wm8310_devs, ARRAY_SIZE(wm8310_devs),
1507 NULL, 0);
1508 break;
1509
1510 case WM8311:
1511 ret = mfd_add_devices(wm831x->dev, -1,
1512 wm8311_devs, ARRAY_SIZE(wm8311_devs),
1513 NULL, 0);
1514 break;
1515
1516 case WM8312:
1517 ret = mfd_add_devices(wm831x->dev, -1,
1518 wm8312_devs, ARRAY_SIZE(wm8312_devs),
1519 NULL, 0);
1520 break;
1521
Mark Brownd4e0a892009-10-01 15:41:07 +01001522 case WM8320:
1523 ret = mfd_add_devices(wm831x->dev, -1,
1524 wm8320_devs, ARRAY_SIZE(wm8320_devs),
1525 NULL, 0);
1526 break;
1527
Mark Brownd2bedfe2009-07-27 14:45:52 +01001528 default:
1529 /* If this happens the bus probe function is buggy */
1530 BUG();
1531 }
1532
1533 if (ret != 0) {
1534 dev_err(wm831x->dev, "Failed to add children\n");
Mark Brown7d4d0a32009-07-27 14:45:53 +01001535 goto err_irq;
Mark Brownd2bedfe2009-07-27 14:45:52 +01001536 }
1537
Mark Brown63aed852009-07-27 14:45:55 +01001538 if (pdata && pdata->backlight) {
1539 /* Treat errors as non-critical */
1540 ret = mfd_add_devices(wm831x->dev, -1, backlight_devs,
1541 ARRAY_SIZE(backlight_devs), NULL, 0);
1542 if (ret < 0)
1543 dev_err(wm831x->dev, "Failed to add backlight: %d\n",
1544 ret);
1545 }
1546
Mark Brown6704e512009-07-27 14:45:56 +01001547 wm831x_otp_init(wm831x);
1548
Mark Brownd2bedfe2009-07-27 14:45:52 +01001549 if (pdata && pdata->post_init) {
1550 ret = pdata->post_init(wm831x);
1551 if (ret != 0) {
1552 dev_err(wm831x->dev, "post_init() failed: %d\n", ret);
Mark Brown7d4d0a32009-07-27 14:45:53 +01001553 goto err_irq;
Mark Brownd2bedfe2009-07-27 14:45:52 +01001554 }
1555 }
1556
1557 return 0;
1558
Mark Brown7d4d0a32009-07-27 14:45:53 +01001559err_irq:
1560 wm831x_irq_exit(wm831x);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001561err:
1562 mfd_remove_devices(wm831x->dev);
1563 kfree(wm831x);
1564 return ret;
1565}
1566
1567static void wm831x_device_exit(struct wm831x *wm831x)
1568{
Mark Brown6704e512009-07-27 14:45:56 +01001569 wm831x_otp_exit(wm831x);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001570 mfd_remove_devices(wm831x->dev);
Mark Brown7d4d0a32009-07-27 14:45:53 +01001571 wm831x_irq_exit(wm831x);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001572 kfree(wm831x);
1573}
1574
1575static int wm831x_i2c_read_device(struct wm831x *wm831x, unsigned short reg,
1576 int bytes, void *dest)
1577{
1578 struct i2c_client *i2c = wm831x->control_data;
1579 int ret;
1580 u16 r = cpu_to_be16(reg);
1581
1582 ret = i2c_master_send(i2c, (unsigned char *)&r, 2);
1583 if (ret < 0)
1584 return ret;
1585 if (ret != 2)
1586 return -EIO;
1587
1588 ret = i2c_master_recv(i2c, dest, bytes);
1589 if (ret < 0)
1590 return ret;
1591 if (ret != bytes)
1592 return -EIO;
1593 return 0;
1594}
1595
1596/* Currently we allocate the write buffer on the stack; this is OK for
1597 * small writes - if we need to do large writes this will need to be
1598 * revised.
1599 */
1600static int wm831x_i2c_write_device(struct wm831x *wm831x, unsigned short reg,
1601 int bytes, void *src)
1602{
1603 struct i2c_client *i2c = wm831x->control_data;
1604 unsigned char msg[bytes + 2];
1605 int ret;
1606
1607 reg = cpu_to_be16(reg);
1608 memcpy(&msg[0], &reg, 2);
1609 memcpy(&msg[2], src, bytes);
1610
1611 ret = i2c_master_send(i2c, msg, bytes + 2);
1612 if (ret < 0)
1613 return ret;
1614 if (ret < bytes + 2)
1615 return -EIO;
1616
1617 return 0;
1618}
1619
1620static int wm831x_i2c_probe(struct i2c_client *i2c,
1621 const struct i2c_device_id *id)
1622{
1623 struct wm831x *wm831x;
1624
1625 wm831x = kzalloc(sizeof(struct wm831x), GFP_KERNEL);
1626 if (wm831x == NULL) {
1627 kfree(i2c);
1628 return -ENOMEM;
1629 }
1630
1631 i2c_set_clientdata(i2c, wm831x);
1632 wm831x->dev = &i2c->dev;
1633 wm831x->control_data = i2c;
1634 wm831x->read_dev = wm831x_i2c_read_device;
1635 wm831x->write_dev = wm831x_i2c_write_device;
1636
1637 return wm831x_device_init(wm831x, id->driver_data, i2c->irq);
1638}
1639
1640static int wm831x_i2c_remove(struct i2c_client *i2c)
1641{
1642 struct wm831x *wm831x = i2c_get_clientdata(i2c);
1643
1644 wm831x_device_exit(wm831x);
1645
1646 return 0;
1647}
1648
1649static const struct i2c_device_id wm831x_i2c_id[] = {
1650 { "wm8310", WM8310 },
1651 { "wm8311", WM8311 },
1652 { "wm8312", WM8312 },
Mark Brownd4e0a892009-10-01 15:41:07 +01001653 { "wm8320", WM8320 },
Mark Brownd2bedfe2009-07-27 14:45:52 +01001654 { }
1655};
1656MODULE_DEVICE_TABLE(i2c, wm831x_i2c_id);
1657
1658
1659static struct i2c_driver wm831x_i2c_driver = {
1660 .driver = {
1661 .name = "wm831x",
1662 .owner = THIS_MODULE,
1663 },
1664 .probe = wm831x_i2c_probe,
1665 .remove = wm831x_i2c_remove,
1666 .id_table = wm831x_i2c_id,
1667};
1668
1669static int __init wm831x_i2c_init(void)
1670{
1671 int ret;
1672
1673 ret = i2c_add_driver(&wm831x_i2c_driver);
1674 if (ret != 0)
1675 pr_err("Failed to register wm831x I2C driver: %d\n", ret);
1676
1677 return ret;
1678}
1679subsys_initcall(wm831x_i2c_init);
1680
1681static void __exit wm831x_i2c_exit(void)
1682{
1683 i2c_del_driver(&wm831x_i2c_driver);
1684}
1685module_exit(wm831x_i2c_exit);
1686
1687MODULE_DESCRIPTION("I2C support for the WM831X AudioPlus PMIC");
1688MODULE_LICENSE("GPL");
1689MODULE_AUTHOR("Mark Brown");