diff options
-rw-r--r-- | drivers/mfd/wm831x-core.c | 1357 | ||||
-rw-r--r-- | include/linux/mfd/wm831x/core.h | 247 | ||||
-rw-r--r-- | include/linux/mfd/wm831x/pdata.h | 107 |
3 files changed, 1711 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 | |||
23 | enum wm831x_parent { | ||
24 | WM8310 = 0, | ||
25 | WM8311 = 1, | ||
26 | WM8312 = 2, | ||
27 | }; | ||
28 | |||
29 | static 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 | */ | ||
55 | void 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 | } | ||
72 | EXPORT_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 | */ | ||
81 | int 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 | } | ||
98 | EXPORT_SYMBOL_GPL(wm831x_reg_unlock); | ||
99 | |||
100 | static 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 | */ | ||
129 | int 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 | } | ||
145 | EXPORT_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 | */ | ||
155 | int 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 | } | ||
168 | EXPORT_SYMBOL_GPL(wm831x_bulk_read); | ||
169 | |||
170 | static 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 | */ | ||
199 | int 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 | } | ||
212 | EXPORT_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 | */ | ||
222 | int 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 | |||
239 | out: | ||
240 | mutex_unlock(&wm831x->io_lock); | ||
241 | |||
242 | return ret; | ||
243 | } | ||
244 | EXPORT_SYMBOL_GPL(wm831x_set_bits); | ||
245 | |||
246 | static 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 | |||
267 | static 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 | |||
287 | static 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 | |||
301 | static 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 | |||
315 | static 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 | |||
323 | static 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 | |||
336 | static 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 | |||
349 | static 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 | |||
363 | static 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 | |||
377 | static 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 | |||
391 | static 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 | |||
405 | static 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 | |||
419 | static 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 | |||
433 | static 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 | |||
447 | static 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 | |||
461 | static 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 | |||
475 | static 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 | |||
489 | static 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 | |||
497 | static struct resource wm831x_on_resources[] = { | ||
498 | { | ||
499 | .start = WM831X_IRQ_ON, | ||
500 | .end = WM831X_IRQ_ON, | ||
501 | .flags = IORESOURCE_IRQ, | ||
502 | }, | ||
503 | }; | ||
504 | |||
505 | |||
506 | static 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 | |||
575 | static 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 | |||
590 | static 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 | |||
598 | static 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 | |||
606 | static 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 | |||
621 | static 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 | |||
629 | static 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 | |||
782 | static 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 | |||
916 | static 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 | */ | ||
1077 | static 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 | |||
1232 | err: | ||
1233 | mfd_remove_devices(wm831x->dev); | ||
1234 | kfree(wm831x); | ||
1235 | return ret; | ||
1236 | } | ||
1237 | |||
1238 | static void wm831x_device_exit(struct wm831x *wm831x) | ||
1239 | { | ||
1240 | mfd_remove_devices(wm831x->dev); | ||
1241 | kfree(wm831x); | ||
1242 | } | ||
1243 | |||
1244 | static 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 | */ | ||
1269 | static 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], ®, 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 | |||
1289 | static 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 | |||
1309 | static 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 | |||
1318 | static const struct i2c_device_id wm831x_i2c_id[] = { | ||
1319 | { "wm8310", WM8310 }, | ||
1320 | { "wm8311", WM8311 }, | ||
1321 | { "wm8312", WM8312 }, | ||
1322 | { } | ||
1323 | }; | ||
1324 | MODULE_DEVICE_TABLE(i2c, wm831x_i2c_id); | ||
1325 | |||
1326 | |||
1327 | static 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 | |||
1337 | static 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 | } | ||
1347 | subsys_initcall(wm831x_i2c_init); | ||
1348 | |||
1349 | static void __exit wm831x_i2c_exit(void) | ||
1350 | { | ||
1351 | i2c_del_driver(&wm831x_i2c_driver); | ||
1352 | } | ||
1353 | module_exit(wm831x_i2c_exit); | ||
1354 | |||
1355 | MODULE_DESCRIPTION("I2C support for the WM831X AudioPlus PMIC"); | ||
1356 | MODULE_LICENSE("GPL"); | ||
1357 | MODULE_AUTHOR("Mark Brown"); | ||
diff --git a/include/linux/mfd/wm831x/core.h b/include/linux/mfd/wm831x/core.h new file mode 100644 index 000000000000..d90e693053ba --- /dev/null +++ b/include/linux/mfd/wm831x/core.h | |||
@@ -0,0 +1,247 @@ | |||
1 | /* | ||
2 | * include/linux/mfd/wm831x/core.h -- Core interface for WM831x | ||
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 | #ifndef __MFD_WM831X_CORE_H__ | ||
16 | #define __MFD_WM831X_CORE_H__ | ||
17 | |||
18 | /* | ||
19 | * Register values. | ||
20 | */ | ||
21 | #define WM831X_RESET_ID 0x00 | ||
22 | #define WM831X_REVISION 0x01 | ||
23 | #define WM831X_PARENT_ID 0x4000 | ||
24 | #define WM831X_SYSVDD_CONTROL 0x4001 | ||
25 | #define WM831X_THERMAL_MONITORING 0x4002 | ||
26 | #define WM831X_POWER_STATE 0x4003 | ||
27 | #define WM831X_WATCHDOG 0x4004 | ||
28 | #define WM831X_ON_PIN_CONTROL 0x4005 | ||
29 | #define WM831X_RESET_CONTROL 0x4006 | ||
30 | #define WM831X_CONTROL_INTERFACE 0x4007 | ||
31 | #define WM831X_SECURITY_KEY 0x4008 | ||
32 | #define WM831X_SOFTWARE_SCRATCH 0x4009 | ||
33 | #define WM831X_OTP_CONTROL 0x400A | ||
34 | #define WM831X_GPIO_LEVEL 0x400C | ||
35 | #define WM831X_SYSTEM_STATUS 0x400D | ||
36 | #define WM831X_ON_SOURCE 0x400E | ||
37 | #define WM831X_OFF_SOURCE 0x400F | ||
38 | #define WM831X_SYSTEM_INTERRUPTS 0x4010 | ||
39 | #define WM831X_INTERRUPT_STATUS_1 0x4011 | ||
40 | #define WM831X_INTERRUPT_STATUS_2 0x4012 | ||
41 | #define WM831X_INTERRUPT_STATUS_3 0x4013 | ||
42 | #define WM831X_INTERRUPT_STATUS_4 0x4014 | ||
43 | #define WM831X_INTERRUPT_STATUS_5 0x4015 | ||
44 | #define WM831X_IRQ_CONFIG 0x4017 | ||
45 | #define WM831X_SYSTEM_INTERRUPTS_MASK 0x4018 | ||
46 | #define WM831X_INTERRUPT_STATUS_1_MASK 0x4019 | ||
47 | #define WM831X_INTERRUPT_STATUS_2_MASK 0x401A | ||
48 | #define WM831X_INTERRUPT_STATUS_3_MASK 0x401B | ||
49 | #define WM831X_INTERRUPT_STATUS_4_MASK 0x401C | ||
50 | #define WM831X_INTERRUPT_STATUS_5_MASK 0x401D | ||
51 | #define WM831X_RTC_WRITE_COUNTER 0x4020 | ||
52 | #define WM831X_RTC_TIME_1 0x4021 | ||
53 | #define WM831X_RTC_TIME_2 0x4022 | ||
54 | #define WM831X_RTC_ALARM_1 0x4023 | ||
55 | #define WM831X_RTC_ALARM_2 0x4024 | ||
56 | #define WM831X_RTC_CONTROL 0x4025 | ||
57 | #define WM831X_RTC_TRIM 0x4026 | ||
58 | #define WM831X_TOUCH_CONTROL_1 0x4028 | ||
59 | #define WM831X_TOUCH_CONTROL_2 0x4029 | ||
60 | #define WM831X_TOUCH_DATA_X 0x402A | ||
61 | #define WM831X_TOUCH_DATA_Y 0x402B | ||
62 | #define WM831X_TOUCH_DATA_Z 0x402C | ||
63 | #define WM831X_AUXADC_DATA 0x402D | ||
64 | #define WM831X_AUXADC_CONTROL 0x402E | ||
65 | #define WM831X_AUXADC_SOURCE 0x402F | ||
66 | #define WM831X_COMPARATOR_CONTROL 0x4030 | ||
67 | #define WM831X_COMPARATOR_1 0x4031 | ||
68 | #define WM831X_COMPARATOR_2 0x4032 | ||
69 | #define WM831X_COMPARATOR_3 0x4033 | ||
70 | #define WM831X_COMPARATOR_4 0x4034 | ||
71 | #define WM831X_GPIO1_CONTROL 0x4038 | ||
72 | #define WM831X_GPIO2_CONTROL 0x4039 | ||
73 | #define WM831X_GPIO3_CONTROL 0x403A | ||
74 | #define WM831X_GPIO4_CONTROL 0x403B | ||
75 | #define WM831X_GPIO5_CONTROL 0x403C | ||
76 | #define WM831X_GPIO6_CONTROL 0x403D | ||
77 | #define WM831X_GPIO7_CONTROL 0x403E | ||
78 | #define WM831X_GPIO8_CONTROL 0x403F | ||
79 | #define WM831X_GPIO9_CONTROL 0x4040 | ||
80 | #define WM831X_GPIO10_CONTROL 0x4041 | ||
81 | #define WM831X_GPIO11_CONTROL 0x4042 | ||
82 | #define WM831X_GPIO12_CONTROL 0x4043 | ||
83 | #define WM831X_GPIO13_CONTROL 0x4044 | ||
84 | #define WM831X_GPIO14_CONTROL 0x4045 | ||
85 | #define WM831X_GPIO15_CONTROL 0x4046 | ||
86 | #define WM831X_GPIO16_CONTROL 0x4047 | ||
87 | #define WM831X_CHARGER_CONTROL_1 0x4048 | ||
88 | #define WM831X_CHARGER_CONTROL_2 0x4049 | ||
89 | #define WM831X_CHARGER_STATUS 0x404A | ||
90 | #define WM831X_BACKUP_CHARGER_CONTROL 0x404B | ||
91 | #define WM831X_STATUS_LED_1 0x404C | ||
92 | #define WM831X_STATUS_LED_2 0x404D | ||
93 | #define WM831X_CURRENT_SINK_1 0x404E | ||
94 | #define WM831X_CURRENT_SINK_2 0x404F | ||
95 | #define WM831X_DCDC_ENABLE 0x4050 | ||
96 | #define WM831X_LDO_ENABLE 0x4051 | ||
97 | #define WM831X_DCDC_STATUS 0x4052 | ||
98 | #define WM831X_LDO_STATUS 0x4053 | ||
99 | #define WM831X_DCDC_UV_STATUS 0x4054 | ||
100 | #define WM831X_LDO_UV_STATUS 0x4055 | ||
101 | #define WM831X_DC1_CONTROL_1 0x4056 | ||
102 | #define WM831X_DC1_CONTROL_2 0x4057 | ||
103 | #define WM831X_DC1_ON_CONFIG 0x4058 | ||
104 | #define WM831X_DC1_SLEEP_CONTROL 0x4059 | ||
105 | #define WM831X_DC1_DVS_CONTROL 0x405A | ||
106 | #define WM831X_DC2_CONTROL_1 0x405B | ||
107 | #define WM831X_DC2_CONTROL_2 0x405C | ||
108 | #define WM831X_DC2_ON_CONFIG 0x405D | ||
109 | #define WM831X_DC2_SLEEP_CONTROL 0x405E | ||
110 | #define WM831X_DC2_DVS_CONTROL 0x405F | ||
111 | #define WM831X_DC3_CONTROL_1 0x4060 | ||
112 | #define WM831X_DC3_CONTROL_2 0x4061 | ||
113 | #define WM831X_DC3_ON_CONFIG 0x4062 | ||
114 | #define WM831X_DC3_SLEEP_CONTROL 0x4063 | ||
115 | #define WM831X_DC4_CONTROL 0x4064 | ||
116 | #define WM831X_DC4_SLEEP_CONTROL 0x4065 | ||
117 | #define WM831X_EPE1_CONTROL 0x4066 | ||
118 | #define WM831X_EPE2_CONTROL 0x4067 | ||
119 | #define WM831X_LDO1_CONTROL 0x4068 | ||
120 | #define WM831X_LDO1_ON_CONTROL 0x4069 | ||
121 | #define WM831X_LDO1_SLEEP_CONTROL 0x406A | ||
122 | #define WM831X_LDO2_CONTROL 0x406B | ||
123 | #define WM831X_LDO2_ON_CONTROL 0x406C | ||
124 | #define WM831X_LDO2_SLEEP_CONTROL 0x406D | ||
125 | #define WM831X_LDO3_CONTROL 0x406E | ||
126 | #define WM831X_LDO3_ON_CONTROL 0x406F | ||
127 | #define WM831X_LDO3_SLEEP_CONTROL 0x4070 | ||
128 | #define WM831X_LDO4_CONTROL 0x4071 | ||
129 | #define WM831X_LDO4_ON_CONTROL 0x4072 | ||
130 | #define WM831X_LDO4_SLEEP_CONTROL 0x4073 | ||
131 | #define WM831X_LDO5_CONTROL 0x4074 | ||
132 | #define WM831X_LDO5_ON_CONTROL 0x4075 | ||
133 | #define WM831X_LDO5_SLEEP_CONTROL 0x4076 | ||
134 | #define WM831X_LDO6_CONTROL 0x4077 | ||
135 | #define WM831X_LDO6_ON_CONTROL 0x4078 | ||
136 | #define WM831X_LDO6_SLEEP_CONTROL 0x4079 | ||
137 | #define WM831X_LDO7_CONTROL 0x407A | ||
138 | #define WM831X_LDO7_ON_CONTROL 0x407B | ||
139 | #define WM831X_LDO7_SLEEP_CONTROL 0x407C | ||
140 | #define WM831X_LDO8_CONTROL 0x407D | ||
141 | #define WM831X_LDO8_ON_CONTROL 0x407E | ||
142 | #define WM831X_LDO8_SLEEP_CONTROL 0x407F | ||
143 | #define WM831X_LDO9_CONTROL 0x4080 | ||
144 | #define WM831X_LDO9_ON_CONTROL 0x4081 | ||
145 | #define WM831X_LDO9_SLEEP_CONTROL 0x4082 | ||
146 | #define WM831X_LDO10_CONTROL 0x4083 | ||
147 | #define WM831X_LDO10_ON_CONTROL 0x4084 | ||
148 | #define WM831X_LDO10_SLEEP_CONTROL 0x4085 | ||
149 | #define WM831X_LDO11_ON_CONTROL 0x4087 | ||
150 | #define WM831X_LDO11_SLEEP_CONTROL 0x4088 | ||
151 | #define WM831X_POWER_GOOD_SOURCE_1 0x408E | ||
152 | #define WM831X_POWER_GOOD_SOURCE_2 0x408F | ||
153 | #define WM831X_CLOCK_CONTROL_1 0x4090 | ||
154 | #define WM831X_CLOCK_CONTROL_2 0x4091 | ||
155 | #define WM831X_FLL_CONTROL_1 0x4092 | ||
156 | #define WM831X_FLL_CONTROL_2 0x4093 | ||
157 | #define WM831X_FLL_CONTROL_3 0x4094 | ||
158 | #define WM831X_FLL_CONTROL_4 0x4095 | ||
159 | #define WM831X_FLL_CONTROL_5 0x4096 | ||
160 | #define WM831X_UNIQUE_ID_1 0x7800 | ||
161 | #define WM831X_UNIQUE_ID_2 0x7801 | ||
162 | #define WM831X_UNIQUE_ID_3 0x7802 | ||
163 | #define WM831X_UNIQUE_ID_4 0x7803 | ||
164 | #define WM831X_UNIQUE_ID_5 0x7804 | ||
165 | #define WM831X_UNIQUE_ID_6 0x7805 | ||
166 | #define WM831X_UNIQUE_ID_7 0x7806 | ||
167 | #define WM831X_UNIQUE_ID_8 0x7807 | ||
168 | #define WM831X_FACTORY_OTP_ID 0x7808 | ||
169 | #define WM831X_FACTORY_OTP_1 0x7809 | ||
170 | #define WM831X_FACTORY_OTP_2 0x780A | ||
171 | #define WM831X_FACTORY_OTP_3 0x780B | ||
172 | #define WM831X_FACTORY_OTP_4 0x780C | ||
173 | #define WM831X_FACTORY_OTP_5 0x780D | ||
174 | #define WM831X_CUSTOMER_OTP_ID 0x7810 | ||
175 | #define WM831X_DC1_OTP_CONTROL 0x7811 | ||
176 | #define WM831X_DC2_OTP_CONTROL 0x7812 | ||
177 | #define WM831X_DC3_OTP_CONTROL 0x7813 | ||
178 | #define WM831X_LDO1_2_OTP_CONTROL 0x7814 | ||
179 | #define WM831X_LDO3_4_OTP_CONTROL 0x7815 | ||
180 | #define WM831X_LDO5_6_OTP_CONTROL 0x7816 | ||
181 | #define WM831X_LDO7_8_OTP_CONTROL 0x7817 | ||
182 | #define WM831X_LDO9_10_OTP_CONTROL 0x7818 | ||
183 | #define WM831X_LDO11_EPE_CONTROL 0x7819 | ||
184 | #define WM831X_GPIO1_OTP_CONTROL 0x781A | ||
185 | #define WM831X_GPIO2_OTP_CONTROL 0x781B | ||
186 | #define WM831X_GPIO3_OTP_CONTROL 0x781C | ||
187 | #define WM831X_GPIO4_OTP_CONTROL 0x781D | ||
188 | #define WM831X_GPIO5_OTP_CONTROL 0x781E | ||
189 | #define WM831X_GPIO6_OTP_CONTROL 0x781F | ||
190 | #define WM831X_DBE_CHECK_DATA 0x7827 | ||
191 | |||
192 | /* | ||
193 | * R0 (0x00) - Reset ID | ||
194 | */ | ||
195 | #define WM831X_CHIP_ID_MASK 0xFFFF /* CHIP_ID - [15:0] */ | ||
196 | #define WM831X_CHIP_ID_SHIFT 0 /* CHIP_ID - [15:0] */ | ||
197 | #define WM831X_CHIP_ID_WIDTH 16 /* CHIP_ID - [15:0] */ | ||
198 | |||
199 | /* | ||
200 | * R1 (0x01) - Revision | ||
201 | */ | ||
202 | #define WM831X_PARENT_REV_MASK 0xFF00 /* PARENT_REV - [15:8] */ | ||
203 | #define WM831X_PARENT_REV_SHIFT 8 /* PARENT_REV - [15:8] */ | ||
204 | #define WM831X_PARENT_REV_WIDTH 8 /* PARENT_REV - [15:8] */ | ||
205 | #define WM831X_CHILD_REV_MASK 0x00FF /* CHILD_REV - [7:0] */ | ||
206 | #define WM831X_CHILD_REV_SHIFT 0 /* CHILD_REV - [7:0] */ | ||
207 | #define WM831X_CHILD_REV_WIDTH 8 /* CHILD_REV - [7:0] */ | ||
208 | |||
209 | /* | ||
210 | * R16384 (0x4000) - Parent ID | ||
211 | */ | ||
212 | #define WM831X_PARENT_ID_MASK 0xFFFF /* PARENT_ID - [15:0] */ | ||
213 | #define WM831X_PARENT_ID_SHIFT 0 /* PARENT_ID - [15:0] */ | ||
214 | #define WM831X_PARENT_ID_WIDTH 16 /* PARENT_ID - [15:0] */ | ||
215 | |||
216 | struct wm831x { | ||
217 | struct mutex io_lock; | ||
218 | |||
219 | struct device *dev; | ||
220 | int (*read_dev)(struct wm831x *wm831x, unsigned short reg, | ||
221 | int bytes, void *dest); | ||
222 | int (*write_dev)(struct wm831x *wm831x, unsigned short reg, | ||
223 | int bytes, void *src); | ||
224 | |||
225 | void *control_data; | ||
226 | |||
227 | /* The WM831x has a security key blocking access to certain | ||
228 | * registers. The mutex is taken by the accessors for locking | ||
229 | * and unlocking the security key, locked is used to fail | ||
230 | * writes if the lock is held. | ||
231 | */ | ||
232 | struct mutex key_lock; | ||
233 | unsigned int locked:1; | ||
234 | }; | ||
235 | |||
236 | /* Device I/O API */ | ||
237 | int wm831x_reg_read(struct wm831x *wm831x, unsigned short reg); | ||
238 | int wm831x_reg_write(struct wm831x *wm831x, unsigned short reg, | ||
239 | unsigned short val); | ||
240 | void wm831x_reg_lock(struct wm831x *wm831x); | ||
241 | int wm831x_reg_unlock(struct wm831x *wm831x); | ||
242 | int wm831x_set_bits(struct wm831x *wm831x, unsigned short reg, | ||
243 | unsigned short mask, unsigned short val); | ||
244 | int wm831x_bulk_read(struct wm831x *wm831x, unsigned short reg, | ||
245 | int count, u16 *buf); | ||
246 | |||
247 | #endif | ||
diff --git a/include/linux/mfd/wm831x/pdata.h b/include/linux/mfd/wm831x/pdata.h new file mode 100644 index 000000000000..571e60136264 --- /dev/null +++ b/include/linux/mfd/wm831x/pdata.h | |||
@@ -0,0 +1,107 @@ | |||
1 | /* | ||
2 | * include/linux/mfd/wm831x/pdata.h -- Platform data for WM831x | ||
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 | #ifndef __MFD_WM831X_PDATA_H__ | ||
16 | #define __MFD_WM831X_PDATA_H__ | ||
17 | |||
18 | struct wm831x; | ||
19 | struct regulator_init_data; | ||
20 | |||
21 | struct wm831x_backup_pdata { | ||
22 | int charger_enable; | ||
23 | int no_constant_voltage; /** Disable constant voltage charging */ | ||
24 | int vlim; /** Voltage limit in milivolts */ | ||
25 | int ilim; /** Current limit in microamps */ | ||
26 | }; | ||
27 | |||
28 | struct wm831x_battery_pdata { | ||
29 | int enable; /** Enable charging */ | ||
30 | int fast_enable; /** Enable fast charging */ | ||
31 | int off_mask; /** Mask OFF while charging */ | ||
32 | int trickle_ilim; /** Trickle charge current limit, in mA */ | ||
33 | int vsel; /** Target voltage, in mV */ | ||
34 | int eoc_iterm; /** End of trickle charge current, in mA */ | ||
35 | int fast_ilim; /** Fast charge current limit, in mA */ | ||
36 | int timeout; /** Charge cycle timeout, in minutes */ | ||
37 | }; | ||
38 | |||
39 | /* Sources for status LED configuration. Values are register values | ||
40 | * plus 1 to allow for a zero default for preserve. | ||
41 | */ | ||
42 | enum wm831x_status_src { | ||
43 | WM831X_STATUS_PRESERVE = 0, /* Keep the current hardware setting */ | ||
44 | WM831X_STATUS_OTP = 1, | ||
45 | WM831X_STATUS_POWER = 2, | ||
46 | WM831X_STATUS_CHARGER = 3, | ||
47 | WM831X_STATUS_MANUAL = 4, | ||
48 | }; | ||
49 | |||
50 | struct wm831x_status_pdata { | ||
51 | enum wm831x_status_src default_src; | ||
52 | const char *name; | ||
53 | const char *default_trigger; | ||
54 | }; | ||
55 | |||
56 | struct wm831x_touch_pdata { | ||
57 | int fivewire; /** 1 for five wire mode, 0 for 4 wire */ | ||
58 | int isel; /** Current for pen down (uA) */ | ||
59 | int rpu; /** Pen down sensitivity resistor divider */ | ||
60 | int pressure; /** Report pressure (boolean) */ | ||
61 | int data_irq; /** Touch data ready IRQ */ | ||
62 | }; | ||
63 | |||
64 | enum wm831x_watchdog_action { | ||
65 | WM831X_WDOG_NONE = 0, | ||
66 | WM831X_WDOG_INTERRUPT = 1, | ||
67 | WM831X_WDOG_RESET = 2, | ||
68 | WM831X_WDOG_WAKE = 3, | ||
69 | }; | ||
70 | |||
71 | struct wm831x_watchdog_pdata { | ||
72 | enum wm831x_watchdog_action primary, secondary; | ||
73 | int update_gpio; | ||
74 | unsigned int software:1; | ||
75 | }; | ||
76 | |||
77 | #define WM831X_MAX_STATUS 2 | ||
78 | #define WM831X_MAX_DCDC 4 | ||
79 | #define WM831X_MAX_EPE 2 | ||
80 | #define WM831X_MAX_LDO 11 | ||
81 | #define WM831X_MAX_ISINK 2 | ||
82 | |||
83 | struct wm831x_pdata { | ||
84 | /** Called before subdevices are set up */ | ||
85 | int (*pre_init)(struct wm831x *wm831x); | ||
86 | /** Called after subdevices are set up */ | ||
87 | int (*post_init)(struct wm831x *wm831x); | ||
88 | |||
89 | int gpio_base; | ||
90 | struct wm831x_backup_pdata *backup; | ||
91 | struct wm831x_battery_pdata *battery; | ||
92 | struct wm831x_touch_pdata *touch; | ||
93 | struct wm831x_watchdog_pdata *watchdog; | ||
94 | |||
95 | /** LED1 = 0 and so on */ | ||
96 | struct wm831x_status_pdata *status[WM831X_MAX_STATUS]; | ||
97 | /** DCDC1 = 0 and so on */ | ||
98 | struct regulator_init_data *dcdc[WM831X_MAX_DCDC]; | ||
99 | /** EPE1 = 0 and so on */ | ||
100 | struct regulator_init_data *epe[WM831X_MAX_EPE]; | ||
101 | /** LDO1 = 0 and so on */ | ||
102 | struct regulator_init_data *ldo[WM831X_MAX_LDO]; | ||
103 | /** ISINK1 = 0 and so on*/ | ||
104 | struct regulator_init_data *isink[WM831X_MAX_ISINK]; | ||
105 | }; | ||
106 | |||
107 | #endif | ||