aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2009-07-27 09:45:52 -0400
committerSamuel Ortiz <sameo@linux.intel.com>2009-09-17 03:46:57 -0400
commitd2bedfe7a8b2f34beee2cad9cae74a088ee8ed07 (patch)
tree51b84067f1185887a8bb7f95f47240d8367864a5 /drivers
parent3bed6e415fc2cbf8d706848a62a48aebe84435e5 (diff)
mfd: Initial core support for WM831x series devices
The WM831x series of devices are register compatible processor power management subsystems, providing regulator and power path management facilities along with other services like watchdog, RTC and touch panel controllers. This patch adds very basic support, providing basic single register I2C access, handling of the security key and registration of the devices. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mfd/wm831x-core.c1357
1 files changed, 1357 insertions, 0 deletions
diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c
new file mode 100644
index 000000000000..cc1040c9d46c
--- /dev/null
+++ b/drivers/mfd/wm831x-core.c
@@ -0,0 +1,1357 @@
1/*
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>
18#include <linux/mfd/core.h>
19
20#include <linux/mfd/wm831x/core.h>
21#include <linux/mfd/wm831x/pdata.h>
22
23enum wm831x_parent {
24 WM8310 = 0,
25 WM8311 = 1,
26 WM8312 = 2,
27};
28
29static int wm831x_reg_locked(struct wm831x *wm831x, unsigned short reg)
30{
31 if (!wm831x->locked)
32 return 0;
33
34 switch (reg) {
35 case WM831X_WATCHDOG:
36 case WM831X_DC4_CONTROL:
37 case WM831X_ON_PIN_CONTROL:
38 case WM831X_BACKUP_CHARGER_CONTROL:
39 case WM831X_CHARGER_CONTROL_1:
40 case WM831X_CHARGER_CONTROL_2:
41 return 1;
42
43 default:
44 return 0;
45 }
46}
47
48/**
49 * wm831x_reg_unlock: Unlock user keyed registers
50 *
51 * The WM831x has a user key preventing writes to particularly
52 * critical registers. This function locks those registers,
53 * allowing writes to them.
54 */
55void wm831x_reg_lock(struct wm831x *wm831x)
56{
57 int ret;
58
59 ret = wm831x_reg_write(wm831x, WM831X_SECURITY_KEY, 0);
60 if (ret == 0) {
61 dev_vdbg(wm831x->dev, "Registers locked\n");
62
63 mutex_lock(&wm831x->io_lock);
64 WARN_ON(wm831x->locked);
65 wm831x->locked = 1;
66 mutex_unlock(&wm831x->io_lock);
67 } else {
68 dev_err(wm831x->dev, "Failed to lock registers: %d\n", ret);
69 }
70
71}
72EXPORT_SYMBOL_GPL(wm831x_reg_lock);
73
74/**
75 * wm831x_reg_unlock: Unlock user keyed registers
76 *
77 * The WM831x has a user key preventing writes to particularly
78 * critical registers. This function locks those registers,
79 * preventing spurious writes.
80 */
81int wm831x_reg_unlock(struct wm831x *wm831x)
82{
83 int ret;
84
85 /* 0x9716 is the value required to unlock the registers */
86 ret = wm831x_reg_write(wm831x, WM831X_SECURITY_KEY, 0x9716);
87 if (ret == 0) {
88 dev_vdbg(wm831x->dev, "Registers unlocked\n");
89
90 mutex_lock(&wm831x->io_lock);
91 WARN_ON(!wm831x->locked);
92 wm831x->locked = 0;
93 mutex_unlock(&wm831x->io_lock);
94 }
95
96 return ret;
97}
98EXPORT_SYMBOL_GPL(wm831x_reg_unlock);
99
100static int wm831x_read(struct wm831x *wm831x, unsigned short reg,
101 int bytes, void *dest)
102{
103 int ret, i;
104 u16 *buf = dest;
105
106 BUG_ON(bytes % 2);
107 BUG_ON(bytes <= 0);
108
109 ret = wm831x->read_dev(wm831x, reg, bytes, dest);
110 if (ret < 0)
111 return ret;
112
113 for (i = 0; i < bytes / 2; i++) {
114 buf[i] = be16_to_cpu(buf[i]);
115
116 dev_vdbg(wm831x->dev, "Read %04x from R%d(0x%x)\n",
117 buf[i], reg + i, reg + i);
118 }
119
120 return 0;
121}
122
123/**
124 * wm831x_reg_read: Read a single WM831x register.
125 *
126 * @wm831x: Device to read from.
127 * @reg: Register to read.
128 */
129int wm831x_reg_read(struct wm831x *wm831x, unsigned short reg)
130{
131 unsigned short val;
132 int ret;
133
134 mutex_lock(&wm831x->io_lock);
135
136 ret = wm831x_read(wm831x, reg, 2, &val);
137
138 mutex_unlock(&wm831x->io_lock);
139
140 if (ret < 0)
141 return ret;
142 else
143 return val;
144}
145EXPORT_SYMBOL_GPL(wm831x_reg_read);
146
147/**
148 * wm831x_bulk_read: Read multiple WM831x registers
149 *
150 * @wm831x: Device to read from
151 * @reg: First register
152 * @count: Number of registers
153 * @buf: Buffer to fill.
154 */
155int wm831x_bulk_read(struct wm831x *wm831x, unsigned short reg,
156 int count, u16 *buf)
157{
158 int ret;
159
160 mutex_lock(&wm831x->io_lock);
161
162 ret = wm831x_read(wm831x, reg, count * 2, buf);
163
164 mutex_unlock(&wm831x->io_lock);
165
166 return ret;
167}
168EXPORT_SYMBOL_GPL(wm831x_bulk_read);
169
170static int wm831x_write(struct wm831x *wm831x, unsigned short reg,
171 int bytes, void *src)
172{
173 u16 *buf = src;
174 int i;
175
176 BUG_ON(bytes % 2);
177 BUG_ON(bytes <= 0);
178
179 for (i = 0; i < bytes / 2; i++) {
180 if (wm831x_reg_locked(wm831x, reg))
181 return -EPERM;
182
183 dev_vdbg(wm831x->dev, "Write %04x to R%d(0x%x)\n",
184 buf[i], reg + i, reg + i);
185
186 buf[i] = cpu_to_be16(buf[i]);
187 }
188
189 return wm831x->write_dev(wm831x, reg, bytes, src);
190}
191
192/**
193 * wm831x_reg_write: Write a single WM831x register.
194 *
195 * @wm831x: Device to write to.
196 * @reg: Register to write to.
197 * @val: Value to write.
198 */
199int wm831x_reg_write(struct wm831x *wm831x, unsigned short reg,
200 unsigned short val)
201{
202 int ret;
203
204 mutex_lock(&wm831x->io_lock);
205
206 ret = wm831x_write(wm831x, reg, 2, &val);
207
208 mutex_unlock(&wm831x->io_lock);
209
210 return ret;
211}
212EXPORT_SYMBOL_GPL(wm831x_reg_write);
213
214/**
215 * wm831x_set_bits: Set the value of a bitfield in a WM831x register
216 *
217 * @wm831x: Device to write to.
218 * @reg: Register to write to.
219 * @mask: Mask of bits to set.
220 * @val: Value to set (unshifted)
221 */
222int wm831x_set_bits(struct wm831x *wm831x, unsigned short reg,
223 unsigned short mask, unsigned short val)
224{
225 int ret;
226 u16 r;
227
228 mutex_lock(&wm831x->io_lock);
229
230 ret = wm831x_read(wm831x, reg, 2, &r);
231 if (ret < 0)
232 goto out;
233
234 r &= ~mask;
235 r |= val;
236
237 ret = wm831x_write(wm831x, reg, 2, &r);
238
239out:
240 mutex_unlock(&wm831x->io_lock);
241
242 return ret;
243}
244EXPORT_SYMBOL_GPL(wm831x_set_bits);
245
246static struct resource wm831x_dcdc1_resources[] = {
247 {
248 .start = WM831X_DC1_CONTROL_1,
249 .end = WM831X_DC1_DVS_CONTROL,
250 .flags = IORESOURCE_IO,
251 },
252 {
253 .name = "UV",
254 .start = WM831X_IRQ_UV_DC1,
255 .end = WM831X_IRQ_UV_DC1,
256 .flags = IORESOURCE_IRQ,
257 },
258 {
259 .name = "HC",
260 .start = WM831X_IRQ_HC_DC1,
261 .end = WM831X_IRQ_HC_DC1,
262 .flags = IORESOURCE_IRQ,
263 },
264};
265
266
267static struct resource wm831x_dcdc2_resources[] = {
268 {
269 .start = WM831X_DC2_CONTROL_1,
270 .end = WM831X_DC2_DVS_CONTROL,
271 .flags = IORESOURCE_IO,
272 },
273 {
274 .name = "UV",
275 .start = WM831X_IRQ_UV_DC2,
276 .end = WM831X_IRQ_UV_DC2,
277 .flags = IORESOURCE_IRQ,
278 },
279 {
280 .name = "HC",
281 .start = WM831X_IRQ_HC_DC2,
282 .end = WM831X_IRQ_HC_DC2,
283 .flags = IORESOURCE_IRQ,
284 },
285};
286
287static struct resource wm831x_dcdc3_resources[] = {
288 {
289 .start = WM831X_DC3_CONTROL_1,
290 .end = WM831X_DC3_SLEEP_CONTROL,
291 .flags = IORESOURCE_IO,
292 },
293 {
294 .name = "UV",
295 .start = WM831X_IRQ_UV_DC3,
296 .end = WM831X_IRQ_UV_DC3,
297 .flags = IORESOURCE_IRQ,
298 },
299};
300
301static struct resource wm831x_dcdc4_resources[] = {
302 {
303 .start = WM831X_DC4_CONTROL,
304 .end = WM831X_DC4_SLEEP_CONTROL,
305 .flags = IORESOURCE_IO,
306 },
307 {
308 .name = "UV",
309 .start = WM831X_IRQ_UV_DC4,
310 .end = WM831X_IRQ_UV_DC4,
311 .flags = IORESOURCE_IRQ,
312 },
313};
314
315static struct resource wm831x_gpio_resources[] = {
316 {
317 .start = WM831X_IRQ_GPIO_1,
318 .end = WM831X_IRQ_GPIO_16,
319 .flags = IORESOURCE_IRQ,
320 },
321};
322
323static struct resource wm831x_isink1_resources[] = {
324 {
325 .start = WM831X_CURRENT_SINK_1,
326 .end = WM831X_CURRENT_SINK_1,
327 .flags = IORESOURCE_IO,
328 },
329 {
330 .start = WM831X_IRQ_CS1,
331 .end = WM831X_IRQ_CS1,
332 .flags = IORESOURCE_IRQ,
333 },
334};
335
336static struct resource wm831x_isink2_resources[] = {
337 {
338 .start = WM831X_CURRENT_SINK_2,
339 .end = WM831X_CURRENT_SINK_2,
340 .flags = IORESOURCE_IO,
341 },
342 {
343 .start = WM831X_IRQ_CS2,
344 .end = WM831X_IRQ_CS2,
345 .flags = IORESOURCE_IRQ,
346 },
347};
348
349static struct resource wm831x_ldo1_resources[] = {
350 {
351 .start = WM831X_LDO1_CONTROL,
352 .end = WM831X_LDO1_SLEEP_CONTROL,
353 .flags = IORESOURCE_IO,
354 },
355 {
356 .name = "UV",
357 .start = WM831X_IRQ_UV_LDO1,
358 .end = WM831X_IRQ_UV_LDO1,
359 .flags = IORESOURCE_IRQ,
360 },
361};
362
363static struct resource wm831x_ldo2_resources[] = {
364 {
365 .start = WM831X_LDO2_CONTROL,
366 .end = WM831X_LDO2_SLEEP_CONTROL,
367 .flags = IORESOURCE_IO,
368 },
369 {
370 .name = "UV",
371 .start = WM831X_IRQ_UV_LDO2,
372 .end = WM831X_IRQ_UV_LDO2,
373 .flags = IORESOURCE_IRQ,
374 },
375};
376
377static struct resource wm831x_ldo3_resources[] = {
378 {
379 .start = WM831X_LDO3_CONTROL,
380 .end = WM831X_LDO3_SLEEP_CONTROL,
381 .flags = IORESOURCE_IO,
382 },
383 {
384 .name = "UV",
385 .start = WM831X_IRQ_UV_LDO3,
386 .end = WM831X_IRQ_UV_LDO3,
387 .flags = IORESOURCE_IRQ,
388 },
389};
390
391static struct resource wm831x_ldo4_resources[] = {
392 {
393 .start = WM831X_LDO4_CONTROL,
394 .end = WM831X_LDO4_SLEEP_CONTROL,
395 .flags = IORESOURCE_IO,
396 },
397 {
398 .name = "UV",
399 .start = WM831X_IRQ_UV_LDO4,
400 .end = WM831X_IRQ_UV_LDO4,
401 .flags = IORESOURCE_IRQ,
402 },
403};
404
405static struct resource wm831x_ldo5_resources[] = {
406 {
407 .start = WM831X_LDO5_CONTROL,
408 .end = WM831X_LDO5_SLEEP_CONTROL,
409 .flags = IORESOURCE_IO,
410 },
411 {
412 .name = "UV",
413 .start = WM831X_IRQ_UV_LDO5,
414 .end = WM831X_IRQ_UV_LDO5,
415 .flags = IORESOURCE_IRQ,
416 },
417};
418
419static struct resource wm831x_ldo6_resources[] = {
420 {
421 .start = WM831X_LDO6_CONTROL,
422 .end = WM831X_LDO6_SLEEP_CONTROL,
423 .flags = IORESOURCE_IO,
424 },
425 {
426 .name = "UV",
427 .start = WM831X_IRQ_UV_LDO6,
428 .end = WM831X_IRQ_UV_LDO6,
429 .flags = IORESOURCE_IRQ,
430 },
431};
432
433static struct resource wm831x_ldo7_resources[] = {
434 {
435 .start = WM831X_LDO7_CONTROL,
436 .end = WM831X_LDO7_SLEEP_CONTROL,
437 .flags = IORESOURCE_IO,
438 },
439 {
440 .name = "UV",
441 .start = WM831X_IRQ_UV_LDO7,
442 .end = WM831X_IRQ_UV_LDO7,
443 .flags = IORESOURCE_IRQ,
444 },
445};
446
447static struct resource wm831x_ldo8_resources[] = {
448 {
449 .start = WM831X_LDO8_CONTROL,
450 .end = WM831X_LDO8_SLEEP_CONTROL,
451 .flags = IORESOURCE_IO,
452 },
453 {
454 .name = "UV",
455 .start = WM831X_IRQ_UV_LDO8,
456 .end = WM831X_IRQ_UV_LDO8,
457 .flags = IORESOURCE_IRQ,
458 },
459};
460
461static struct resource wm831x_ldo9_resources[] = {
462 {
463 .start = WM831X_LDO9_CONTROL,
464 .end = WM831X_LDO9_SLEEP_CONTROL,
465 .flags = IORESOURCE_IO,
466 },
467 {
468 .name = "UV",
469 .start = WM831X_IRQ_UV_LDO9,
470 .end = WM831X_IRQ_UV_LDO9,
471 .flags = IORESOURCE_IRQ,
472 },
473};
474
475static struct resource wm831x_ldo10_resources[] = {
476 {
477 .start = WM831X_LDO10_CONTROL,
478 .end = WM831X_LDO10_SLEEP_CONTROL,
479 .flags = IORESOURCE_IO,
480 },
481 {
482 .name = "UV",
483 .start = WM831X_IRQ_UV_LDO10,
484 .end = WM831X_IRQ_UV_LDO10,
485 .flags = IORESOURCE_IRQ,
486 },
487};
488
489static struct resource wm831x_ldo11_resources[] = {
490 {
491 .start = WM831X_LDO11_ON_CONTROL,
492 .end = WM831X_LDO11_SLEEP_CONTROL,
493 .flags = IORESOURCE_IO,
494 },
495};
496
497static struct resource wm831x_on_resources[] = {
498 {
499 .start = WM831X_IRQ_ON,
500 .end = WM831X_IRQ_ON,
501 .flags = IORESOURCE_IRQ,
502 },
503};
504
505
506static struct resource wm831x_power_resources[] = {
507 {
508 .name = "SYSLO",
509 .start = WM831X_IRQ_PPM_SYSLO,
510 .end = WM831X_IRQ_PPM_SYSLO,
511 .flags = IORESOURCE_IRQ,
512 },
513 {
514 .name = "PWR SRC",
515 .start = WM831X_IRQ_PPM_PWR_SRC,
516 .end = WM831X_IRQ_PPM_PWR_SRC,
517 .flags = IORESOURCE_IRQ,
518 },
519 {
520 .name = "USB CURR",
521 .start = WM831X_IRQ_PPM_USB_CURR,
522 .end = WM831X_IRQ_PPM_USB_CURR,
523 .flags = IORESOURCE_IRQ,
524 },
525 {
526 .name = "BATT HOT",
527 .start = WM831X_IRQ_CHG_BATT_HOT,
528 .end = WM831X_IRQ_CHG_BATT_HOT,
529 .flags = IORESOURCE_IRQ,
530 },
531 {
532 .name = "BATT COLD",
533 .start = WM831X_IRQ_CHG_BATT_COLD,
534 .end = WM831X_IRQ_CHG_BATT_COLD,
535 .flags = IORESOURCE_IRQ,
536 },
537 {
538 .name = "BATT FAIL",
539 .start = WM831X_IRQ_CHG_BATT_FAIL,
540 .end = WM831X_IRQ_CHG_BATT_FAIL,
541 .flags = IORESOURCE_IRQ,
542 },
543 {
544 .name = "OV",
545 .start = WM831X_IRQ_CHG_OV,
546 .end = WM831X_IRQ_CHG_OV,
547 .flags = IORESOURCE_IRQ,
548 },
549 {
550 .name = "END",
551 .start = WM831X_IRQ_CHG_END,
552 .end = WM831X_IRQ_CHG_END,
553 .flags = IORESOURCE_IRQ,
554 },
555 {
556 .name = "TO",
557 .start = WM831X_IRQ_CHG_TO,
558 .end = WM831X_IRQ_CHG_TO,
559 .flags = IORESOURCE_IRQ,
560 },
561 {
562 .name = "MODE",
563 .start = WM831X_IRQ_CHG_MODE,
564 .end = WM831X_IRQ_CHG_MODE,
565 .flags = IORESOURCE_IRQ,
566 },
567 {
568 .name = "START",
569 .start = WM831X_IRQ_CHG_START,
570 .end = WM831X_IRQ_CHG_START,
571 .flags = IORESOURCE_IRQ,
572 },
573};
574
575static struct resource wm831x_rtc_resources[] = {
576 {
577 .name = "PER",
578 .start = WM831X_IRQ_RTC_PER,
579 .end = WM831X_IRQ_RTC_PER,
580 .flags = IORESOURCE_IRQ,
581 },
582 {
583 .name = "ALM",
584 .start = WM831X_IRQ_RTC_ALM,
585 .end = WM831X_IRQ_RTC_ALM,
586 .flags = IORESOURCE_IRQ,
587 },
588};
589
590static struct resource wm831x_status1_resources[] = {
591 {
592 .start = WM831X_STATUS_LED_1,
593 .end = WM831X_STATUS_LED_1,
594 .flags = IORESOURCE_IO,
595 },
596};
597
598static struct resource wm831x_status2_resources[] = {
599 {
600 .start = WM831X_STATUS_LED_2,
601 .end = WM831X_STATUS_LED_2,
602 .flags = IORESOURCE_IO,
603 },
604};
605
606static struct resource wm831x_touch_resources[] = {
607 {
608 .name = "TCHPD",
609 .start = WM831X_IRQ_TCHPD,
610 .end = WM831X_IRQ_TCHPD,
611 .flags = IORESOURCE_IRQ,
612 },
613 {
614 .name = "TCHDATA",
615 .start = WM831X_IRQ_TCHDATA,
616 .end = WM831X_IRQ_TCHDATA,
617 .flags = IORESOURCE_IRQ,
618 },
619};
620
621static struct resource wm831x_wdt_resources[] = {
622 {
623 .start = WM831X_IRQ_WDOG_TO,
624 .end = WM831X_IRQ_WDOG_TO,
625 .flags = IORESOURCE_IRQ,
626 },
627};
628
629static struct mfd_cell wm8310_devs[] = {
630 {
631 .name = "wm831x-buckv",
632 .id = 1,
633 .num_resources = ARRAY_SIZE(wm831x_dcdc1_resources),
634 .resources = wm831x_dcdc1_resources,
635 },
636 {
637 .name = "wm831x-buckv",
638 .id = 2,
639 .num_resources = ARRAY_SIZE(wm831x_dcdc2_resources),
640 .resources = wm831x_dcdc2_resources,
641 },
642 {
643 .name = "wm831x-buckp",
644 .id = 3,
645 .num_resources = ARRAY_SIZE(wm831x_dcdc3_resources),
646 .resources = wm831x_dcdc3_resources,
647 },
648 {
649 .name = "wm831x-boostp",
650 .id = 4,
651 .num_resources = ARRAY_SIZE(wm831x_dcdc4_resources),
652 .resources = wm831x_dcdc4_resources,
653 },
654 {
655 .name = "wm831x-epe",
656 .id = 1,
657 },
658 {
659 .name = "wm831x-epe",
660 .id = 2,
661 },
662 {
663 .name = "wm831x-gpio",
664 .num_resources = ARRAY_SIZE(wm831x_gpio_resources),
665 .resources = wm831x_gpio_resources,
666 },
667 {
668 .name = "wm831x-hwmon",
669 },
670 {
671 .name = "wm831x-isink",
672 .id = 1,
673 .num_resources = ARRAY_SIZE(wm831x_isink1_resources),
674 .resources = wm831x_isink1_resources,
675 },
676 {
677 .name = "wm831x-isink",
678 .id = 2,
679 .num_resources = ARRAY_SIZE(wm831x_isink2_resources),
680 .resources = wm831x_isink2_resources,
681 },
682 {
683 .name = "wm831x-ldo",
684 .id = 1,
685 .num_resources = ARRAY_SIZE(wm831x_ldo1_resources),
686 .resources = wm831x_ldo1_resources,
687 },
688 {
689 .name = "wm831x-ldo",
690 .id = 2,
691 .num_resources = ARRAY_SIZE(wm831x_ldo2_resources),
692 .resources = wm831x_ldo2_resources,
693 },
694 {
695 .name = "wm831x-ldo",
696 .id = 3,
697 .num_resources = ARRAY_SIZE(wm831x_ldo3_resources),
698 .resources = wm831x_ldo3_resources,
699 },
700 {
701 .name = "wm831x-ldo",
702 .id = 4,
703 .num_resources = ARRAY_SIZE(wm831x_ldo4_resources),
704 .resources = wm831x_ldo4_resources,
705 },
706 {
707 .name = "wm831x-ldo",
708 .id = 5,
709 .num_resources = ARRAY_SIZE(wm831x_ldo5_resources),
710 .resources = wm831x_ldo5_resources,
711 },
712 {
713 .name = "wm831x-ldo",
714 .id = 6,
715 .num_resources = ARRAY_SIZE(wm831x_ldo6_resources),
716 .resources = wm831x_ldo6_resources,
717 },
718 {
719 .name = "wm831x-aldo",
720 .id = 7,
721 .num_resources = ARRAY_SIZE(wm831x_ldo7_resources),
722 .resources = wm831x_ldo7_resources,
723 },
724 {
725 .name = "wm831x-aldo",
726 .id = 8,
727 .num_resources = ARRAY_SIZE(wm831x_ldo8_resources),
728 .resources = wm831x_ldo8_resources,
729 },
730 {
731 .name = "wm831x-aldo",
732 .id = 9,
733 .num_resources = ARRAY_SIZE(wm831x_ldo9_resources),
734 .resources = wm831x_ldo9_resources,
735 },
736 {
737 .name = "wm831x-aldo",
738 .id = 10,
739 .num_resources = ARRAY_SIZE(wm831x_ldo10_resources),
740 .resources = wm831x_ldo10_resources,
741 },
742 {
743 .name = "wm831x-alive-ldo",
744 .id = 11,
745 .num_resources = ARRAY_SIZE(wm831x_ldo11_resources),
746 .resources = wm831x_ldo11_resources,
747 },
748 {
749 .name = "wm831x-on",
750 .num_resources = ARRAY_SIZE(wm831x_on_resources),
751 .resources = wm831x_on_resources,
752 },
753 {
754 .name = "wm831x-power",
755 .num_resources = ARRAY_SIZE(wm831x_power_resources),
756 .resources = wm831x_power_resources,
757 },
758 {
759 .name = "wm831x-rtc",
760 .num_resources = ARRAY_SIZE(wm831x_rtc_resources),
761 .resources = wm831x_rtc_resources,
762 },
763 {
764 .name = "wm831x-status",
765 .id = 1,
766 .num_resources = ARRAY_SIZE(wm831x_status1_resources),
767 .resources = wm831x_status1_resources,
768 },
769 {
770 .name = "wm831x-status",
771 .id = 2,
772 .num_resources = ARRAY_SIZE(wm831x_status2_resources),
773 .resources = wm831x_status2_resources,
774 },
775 {
776 .name = "wm831x-watchdog",
777 .num_resources = ARRAY_SIZE(wm831x_wdt_resources),
778 .resources = wm831x_wdt_resources,
779 },
780};
781
782static struct mfd_cell wm8311_devs[] = {
783 {
784 .name = "wm831x-buckv",
785 .id = 1,
786 .num_resources = ARRAY_SIZE(wm831x_dcdc1_resources),
787 .resources = wm831x_dcdc1_resources,
788 },
789 {
790 .name = "wm831x-buckv",
791 .id = 2,
792 .num_resources = ARRAY_SIZE(wm831x_dcdc2_resources),
793 .resources = wm831x_dcdc2_resources,
794 },
795 {
796 .name = "wm831x-buckp",
797 .id = 3,
798 .num_resources = ARRAY_SIZE(wm831x_dcdc3_resources),
799 .resources = wm831x_dcdc3_resources,
800 },
801 {
802 .name = "wm831x-boostp",
803 .id = 4,
804 .num_resources = ARRAY_SIZE(wm831x_dcdc4_resources),
805 .resources = wm831x_dcdc4_resources,
806 },
807 {
808 .name = "wm831x-epe",
809 .id = 1,
810 },
811 {
812 .name = "wm831x-epe",
813 .id = 2,
814 },
815 {
816 .name = "wm831x-gpio",
817 .num_resources = ARRAY_SIZE(wm831x_gpio_resources),
818 .resources = wm831x_gpio_resources,
819 },
820 {
821 .name = "wm831x-hwmon",
822 },
823 {
824 .name = "wm831x-isink",
825 .id = 1,
826 .num_resources = ARRAY_SIZE(wm831x_isink1_resources),
827 .resources = wm831x_isink1_resources,
828 },
829 {
830 .name = "wm831x-isink",
831 .id = 2,
832 .num_resources = ARRAY_SIZE(wm831x_isink2_resources),
833 .resources = wm831x_isink2_resources,
834 },
835 {
836 .name = "wm831x-ldo",
837 .id = 1,
838 .num_resources = ARRAY_SIZE(wm831x_ldo1_resources),
839 .resources = wm831x_ldo1_resources,
840 },
841 {
842 .name = "wm831x-ldo",
843 .id = 2,
844 .num_resources = ARRAY_SIZE(wm831x_ldo2_resources),
845 .resources = wm831x_ldo2_resources,
846 },
847 {
848 .name = "wm831x-ldo",
849 .id = 3,
850 .num_resources = ARRAY_SIZE(wm831x_ldo3_resources),
851 .resources = wm831x_ldo3_resources,
852 },
853 {
854 .name = "wm831x-ldo",
855 .id = 4,
856 .num_resources = ARRAY_SIZE(wm831x_ldo4_resources),
857 .resources = wm831x_ldo4_resources,
858 },
859 {
860 .name = "wm831x-ldo",
861 .id = 5,
862 .num_resources = ARRAY_SIZE(wm831x_ldo5_resources),
863 .resources = wm831x_ldo5_resources,
864 },
865 {
866 .name = "wm831x-aldo",
867 .id = 7,
868 .num_resources = ARRAY_SIZE(wm831x_ldo7_resources),
869 .resources = wm831x_ldo7_resources,
870 },
871 {
872 .name = "wm831x-alive-ldo",
873 .id = 11,
874 .num_resources = ARRAY_SIZE(wm831x_ldo11_resources),
875 .resources = wm831x_ldo11_resources,
876 },
877 {
878 .name = "wm831x-on",
879 .num_resources = ARRAY_SIZE(wm831x_on_resources),
880 .resources = wm831x_on_resources,
881 },
882 {
883 .name = "wm831x-power",
884 .num_resources = ARRAY_SIZE(wm831x_power_resources),
885 .resources = wm831x_power_resources,
886 },
887 {
888 .name = "wm831x-rtc",
889 .num_resources = ARRAY_SIZE(wm831x_rtc_resources),
890 .resources = wm831x_rtc_resources,
891 },
892 {
893 .name = "wm831x-status",
894 .id = 1,
895 .num_resources = ARRAY_SIZE(wm831x_status1_resources),
896 .resources = wm831x_status1_resources,
897 },
898 {
899 .name = "wm831x-status",
900 .id = 2,
901 .num_resources = ARRAY_SIZE(wm831x_status2_resources),
902 .resources = wm831x_status2_resources,
903 },
904 {
905 .name = "wm831x-touch",
906 .num_resources = ARRAY_SIZE(wm831x_touch_resources),
907 .resources = wm831x_touch_resources,
908 },
909 {
910 .name = "wm831x-watchdog",
911 .num_resources = ARRAY_SIZE(wm831x_wdt_resources),
912 .resources = wm831x_wdt_resources,
913 },
914};
915
916static struct mfd_cell wm8312_devs[] = {
917 {
918 .name = "wm831x-buckv",
919 .id = 1,
920 .num_resources = ARRAY_SIZE(wm831x_dcdc1_resources),
921 .resources = wm831x_dcdc1_resources,
922 },
923 {
924 .name = "wm831x-buckv",
925 .id = 2,
926 .num_resources = ARRAY_SIZE(wm831x_dcdc2_resources),
927 .resources = wm831x_dcdc2_resources,
928 },
929 {
930 .name = "wm831x-buckp",
931 .id = 3,
932 .num_resources = ARRAY_SIZE(wm831x_dcdc3_resources),
933 .resources = wm831x_dcdc3_resources,
934 },
935 {
936 .name = "wm831x-boostp",
937 .id = 4,
938 .num_resources = ARRAY_SIZE(wm831x_dcdc4_resources),
939 .resources = wm831x_dcdc4_resources,
940 },
941 {
942 .name = "wm831x-epe",
943 .id = 1,
944 },
945 {
946 .name = "wm831x-epe",
947 .id = 2,
948 },
949 {
950 .name = "wm831x-gpio",
951 .num_resources = ARRAY_SIZE(wm831x_gpio_resources),
952 .resources = wm831x_gpio_resources,
953 },
954 {
955 .name = "wm831x-hwmon",
956 },
957 {
958 .name = "wm831x-isink",
959 .id = 1,
960 .num_resources = ARRAY_SIZE(wm831x_isink1_resources),
961 .resources = wm831x_isink1_resources,
962 },
963 {
964 .name = "wm831x-isink",
965 .id = 2,
966 .num_resources = ARRAY_SIZE(wm831x_isink2_resources),
967 .resources = wm831x_isink2_resources,
968 },
969 {
970 .name = "wm831x-ldo",
971 .id = 1,
972 .num_resources = ARRAY_SIZE(wm831x_ldo1_resources),
973 .resources = wm831x_ldo1_resources,
974 },
975 {
976 .name = "wm831x-ldo",
977 .id = 2,
978 .num_resources = ARRAY_SIZE(wm831x_ldo2_resources),
979 .resources = wm831x_ldo2_resources,
980 },
981 {
982 .name = "wm831x-ldo",
983 .id = 3,
984 .num_resources = ARRAY_SIZE(wm831x_ldo3_resources),
985 .resources = wm831x_ldo3_resources,
986 },
987 {
988 .name = "wm831x-ldo",
989 .id = 4,
990 .num_resources = ARRAY_SIZE(wm831x_ldo4_resources),
991 .resources = wm831x_ldo4_resources,
992 },
993 {
994 .name = "wm831x-ldo",
995 .id = 5,
996 .num_resources = ARRAY_SIZE(wm831x_ldo5_resources),
997 .resources = wm831x_ldo5_resources,
998 },
999 {
1000 .name = "wm831x-ldo",
1001 .id = 6,
1002 .num_resources = ARRAY_SIZE(wm831x_ldo6_resources),
1003 .resources = wm831x_ldo6_resources,
1004 },
1005 {
1006 .name = "wm831x-aldo",
1007 .id = 7,
1008 .num_resources = ARRAY_SIZE(wm831x_ldo7_resources),
1009 .resources = wm831x_ldo7_resources,
1010 },
1011 {
1012 .name = "wm831x-aldo",
1013 .id = 8,
1014 .num_resources = ARRAY_SIZE(wm831x_ldo8_resources),
1015 .resources = wm831x_ldo8_resources,
1016 },
1017 {
1018 .name = "wm831x-aldo",
1019 .id = 9,
1020 .num_resources = ARRAY_SIZE(wm831x_ldo9_resources),
1021 .resources = wm831x_ldo9_resources,
1022 },
1023 {
1024 .name = "wm831x-aldo",
1025 .id = 10,
1026 .num_resources = ARRAY_SIZE(wm831x_ldo10_resources),
1027 .resources = wm831x_ldo10_resources,
1028 },
1029 {
1030 .name = "wm831x-alive-ldo",
1031 .id = 11,
1032 .num_resources = ARRAY_SIZE(wm831x_ldo11_resources),
1033 .resources = wm831x_ldo11_resources,
1034 },
1035 {
1036 .name = "wm831x-on",
1037 .num_resources = ARRAY_SIZE(wm831x_on_resources),
1038 .resources = wm831x_on_resources,
1039 },
1040 {
1041 .name = "wm831x-power",
1042 .num_resources = ARRAY_SIZE(wm831x_power_resources),
1043 .resources = wm831x_power_resources,
1044 },
1045 {
1046 .name = "wm831x-rtc",
1047 .num_resources = ARRAY_SIZE(wm831x_rtc_resources),
1048 .resources = wm831x_rtc_resources,
1049 },
1050 {
1051 .name = "wm831x-status",
1052 .id = 1,
1053 .num_resources = ARRAY_SIZE(wm831x_status1_resources),
1054 .resources = wm831x_status1_resources,
1055 },
1056 {
1057 .name = "wm831x-status",
1058 .id = 2,
1059 .num_resources = ARRAY_SIZE(wm831x_status2_resources),
1060 .resources = wm831x_status2_resources,
1061 },
1062 {
1063 .name = "wm831x-touch",
1064 .num_resources = ARRAY_SIZE(wm831x_touch_resources),
1065 .resources = wm831x_touch_resources,
1066 },
1067 {
1068 .name = "wm831x-watchdog",
1069 .num_resources = ARRAY_SIZE(wm831x_wdt_resources),
1070 .resources = wm831x_wdt_resources,
1071 },
1072};
1073
1074/*
1075 * Instantiate the generic non-control parts of the device.
1076 */
1077static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
1078{
1079 struct wm831x_pdata *pdata = wm831x->dev->platform_data;
1080 int rev;
1081 enum wm831x_parent parent;
1082 int ret;
1083
1084 mutex_init(&wm831x->io_lock);
1085 mutex_init(&wm831x->key_lock);
1086 dev_set_drvdata(wm831x->dev, wm831x);
1087
1088 ret = wm831x_reg_read(wm831x, WM831X_PARENT_ID);
1089 if (ret < 0) {
1090 dev_err(wm831x->dev, "Failed to read parent ID: %d\n", ret);
1091 goto err;
1092 }
1093 if (ret != 0x6204) {
1094 dev_err(wm831x->dev, "Device is not a WM831x: ID %x\n", ret);
1095 ret = -EINVAL;
1096 goto err;
1097 }
1098
1099 ret = wm831x_reg_read(wm831x, WM831X_REVISION);
1100 if (ret < 0) {
1101 dev_err(wm831x->dev, "Failed to read revision: %d\n", ret);
1102 goto err;
1103 }
1104 rev = (ret & WM831X_PARENT_REV_MASK) >> WM831X_PARENT_REV_SHIFT;
1105
1106 ret = wm831x_reg_read(wm831x, WM831X_RESET_ID);
1107 if (ret < 0) {
1108 dev_err(wm831x->dev, "Failed to read device ID: %d\n", ret);
1109 goto err;
1110 }
1111
1112 switch (ret) {
1113 case 0x8310:
1114 parent = WM8310;
1115 switch (rev) {
1116 case 0:
1117 dev_info(wm831x->dev, "WM8310 revision %c\n",
1118 'A' + rev);
1119 break;
1120 }
1121 break;
1122
1123 case 0x8311:
1124 parent = WM8311;
1125 switch (rev) {
1126 case 0:
1127 dev_info(wm831x->dev, "WM8311 revision %c\n",
1128 'A' + rev);
1129 break;
1130 }
1131 break;
1132
1133 case 0x8312:
1134 parent = WM8312;
1135 switch (rev) {
1136 case 0:
1137 dev_info(wm831x->dev, "WM8312 revision %c\n",
1138 'A' + rev);
1139 break;
1140 }
1141 break;
1142
1143 case 0:
1144 /* Some engineering samples do not have the ID set,
1145 * rely on the device being registered correctly.
1146 * This will need revisiting for future devices with
1147 * multiple dies.
1148 */
1149 parent = id;
1150 switch (rev) {
1151 case 0:
1152 dev_info(wm831x->dev, "WM831%d ES revision %c\n",
1153 parent, 'A' + rev);
1154 break;
1155 }
1156 break;
1157
1158 default:
1159 dev_err(wm831x->dev, "Unknown WM831x device %04x\n", ret);
1160 ret = -EINVAL;
1161 goto err;
1162 }
1163
1164 /* This will need revisiting in future but is OK for all
1165 * current parts.
1166 */
1167 if (parent != id)
1168 dev_warn(wm831x->dev, "Device was registered as a WM831%lu\n",
1169 id);
1170
1171 /* Bootstrap the user key */
1172 ret = wm831x_reg_read(wm831x, WM831X_SECURITY_KEY);
1173 if (ret < 0) {
1174 dev_err(wm831x->dev, "Failed to read security key: %d\n", ret);
1175 goto err;
1176 }
1177 if (ret != 0) {
1178 dev_warn(wm831x->dev, "Security key had non-zero value %x\n",
1179 ret);
1180 wm831x_reg_write(wm831x, WM831X_SECURITY_KEY, 0);
1181 }
1182 wm831x->locked = 1;
1183
1184 if (pdata && pdata->pre_init) {
1185 ret = pdata->pre_init(wm831x);
1186 if (ret != 0) {
1187 dev_err(wm831x->dev, "pre_init() failed: %d\n", ret);
1188 goto err;
1189 }
1190 }
1191
1192 /* The core device is up, instantiate the subdevices. */
1193 switch (parent) {
1194 case WM8310:
1195 ret = mfd_add_devices(wm831x->dev, -1,
1196 wm8310_devs, ARRAY_SIZE(wm8310_devs),
1197 NULL, 0);
1198 break;
1199
1200 case WM8311:
1201 ret = mfd_add_devices(wm831x->dev, -1,
1202 wm8311_devs, ARRAY_SIZE(wm8311_devs),
1203 NULL, 0);
1204 break;
1205
1206 case WM8312:
1207 ret = mfd_add_devices(wm831x->dev, -1,
1208 wm8312_devs, ARRAY_SIZE(wm8312_devs),
1209 NULL, 0);
1210 break;
1211
1212 default:
1213 /* If this happens the bus probe function is buggy */
1214 BUG();
1215 }
1216
1217 if (ret != 0) {
1218 dev_err(wm831x->dev, "Failed to add children\n");
1219 goto err;
1220 }
1221
1222 if (pdata && pdata->post_init) {
1223 ret = pdata->post_init(wm831x);
1224 if (ret != 0) {
1225 dev_err(wm831x->dev, "post_init() failed: %d\n", ret);
1226 goto err;
1227 }
1228 }
1229
1230 return 0;
1231
1232err:
1233 mfd_remove_devices(wm831x->dev);
1234 kfree(wm831x);
1235 return ret;
1236}
1237
1238static void wm831x_device_exit(struct wm831x *wm831x)
1239{
1240 mfd_remove_devices(wm831x->dev);
1241 kfree(wm831x);
1242}
1243
1244static int wm831x_i2c_read_device(struct wm831x *wm831x, unsigned short reg,
1245 int bytes, void *dest)
1246{
1247 struct i2c_client *i2c = wm831x->control_data;
1248 int ret;
1249 u16 r = cpu_to_be16(reg);
1250
1251 ret = i2c_master_send(i2c, (unsigned char *)&r, 2);
1252 if (ret < 0)
1253 return ret;
1254 if (ret != 2)
1255 return -EIO;
1256
1257 ret = i2c_master_recv(i2c, dest, bytes);
1258 if (ret < 0)
1259 return ret;
1260 if (ret != bytes)
1261 return -EIO;
1262 return 0;
1263}
1264
1265/* Currently we allocate the write buffer on the stack; this is OK for
1266 * small writes - if we need to do large writes this will need to be
1267 * revised.
1268 */
1269static int wm831x_i2c_write_device(struct wm831x *wm831x, unsigned short reg,
1270 int bytes, void *src)
1271{
1272 struct i2c_client *i2c = wm831x->control_data;
1273 unsigned char msg[bytes + 2];
1274 int ret;
1275
1276 reg = cpu_to_be16(reg);
1277 memcpy(&msg[0], &reg, 2);
1278 memcpy(&msg[2], src, bytes);
1279
1280 ret = i2c_master_send(i2c, msg, bytes + 2);
1281 if (ret < 0)
1282 return ret;
1283 if (ret < bytes + 2)
1284 return -EIO;
1285
1286 return 0;
1287}
1288
1289static int wm831x_i2c_probe(struct i2c_client *i2c,
1290 const struct i2c_device_id *id)
1291{
1292 struct wm831x *wm831x;
1293
1294 wm831x = kzalloc(sizeof(struct wm831x), GFP_KERNEL);
1295 if (wm831x == NULL) {
1296 kfree(i2c);
1297 return -ENOMEM;
1298 }
1299
1300 i2c_set_clientdata(i2c, wm831x);
1301 wm831x->dev = &i2c->dev;
1302 wm831x->control_data = i2c;
1303 wm831x->read_dev = wm831x_i2c_read_device;
1304 wm831x->write_dev = wm831x_i2c_write_device;
1305
1306 return wm831x_device_init(wm831x, id->driver_data, i2c->irq);
1307}
1308
1309static int wm831x_i2c_remove(struct i2c_client *i2c)
1310{
1311 struct wm831x *wm831x = i2c_get_clientdata(i2c);
1312
1313 wm831x_device_exit(wm831x);
1314
1315 return 0;
1316}
1317
1318static const struct i2c_device_id wm831x_i2c_id[] = {
1319 { "wm8310", WM8310 },
1320 { "wm8311", WM8311 },
1321 { "wm8312", WM8312 },
1322 { }
1323};
1324MODULE_DEVICE_TABLE(i2c, wm831x_i2c_id);
1325
1326
1327static struct i2c_driver wm831x_i2c_driver = {
1328 .driver = {
1329 .name = "wm831x",
1330 .owner = THIS_MODULE,
1331 },
1332 .probe = wm831x_i2c_probe,
1333 .remove = wm831x_i2c_remove,
1334 .id_table = wm831x_i2c_id,
1335};
1336
1337static int __init wm831x_i2c_init(void)
1338{
1339 int ret;
1340
1341 ret = i2c_add_driver(&wm831x_i2c_driver);
1342 if (ret != 0)
1343 pr_err("Failed to register wm831x I2C driver: %d\n", ret);
1344
1345 return ret;
1346}
1347subsys_initcall(wm831x_i2c_init);
1348
1349static void __exit wm831x_i2c_exit(void)
1350{
1351 i2c_del_driver(&wm831x_i2c_driver);
1352}
1353module_exit(wm831x_i2c_exit);
1354
1355MODULE_DESCRIPTION("I2C support for the WM831X AudioPlus PMIC");
1356MODULE_LICENSE("GPL");
1357MODULE_AUTHOR("Mark Brown");