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