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