blob: 25fbbaf39cb9d1d72fa66205d8108a6d4cb32f58 [file] [log] [blame]
Mark Brownd2bedfe2009-07-27 14:45:52 +01001/*
2 * wm831x-core.c -- Device access for Wolfson WM831x PMICs
3 *
4 * Copyright 2009 Wolfson Microelectronics PLC.
5 *
6 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 *
13 */
14
15#include <linux/kernel.h>
Paul Gortmakerefb5a792019-01-13 13:36:46 -050016#include <linux/init.h>
17#include <linux/export.h>
Mark Brown7e9f9fd2009-07-27 14:45:54 +010018#include <linux/bcd.h>
19#include <linux/delay.h>
Mark Brownd2bedfe2009-07-27 14:45:52 +010020#include <linux/mfd/core.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090021#include <linux/slab.h>
Mark Brown1df59812011-06-10 19:28:10 +010022#include <linux/err.h>
Charles Keepaxf6dd8442017-03-17 10:05:18 +000023#include <linux/of.h>
24#include <linux/of_device.h>
Mark Brownd2bedfe2009-07-27 14:45:52 +010025
26#include <linux/mfd/wm831x/core.h>
27#include <linux/mfd/wm831x/pdata.h>
Mark Brown7d4d0a32009-07-27 14:45:53 +010028#include <linux/mfd/wm831x/irq.h>
Mark Brown7e9f9fd2009-07-27 14:45:54 +010029#include <linux/mfd/wm831x/auxadc.h>
Mark Brown6704e512009-07-27 14:45:56 +010030#include <linux/mfd/wm831x/otp.h>
Mark Brown523d9cf2011-09-15 18:54:53 +020031#include <linux/mfd/wm831x/pmu.h>
Mark Brown698659d2009-07-27 14:45:57 +010032#include <linux/mfd/wm831x/regulator.h>
33
34/* Current settings - values are 2*2^(reg_val/4) microamps. These are
35 * exported since they are used by multiple drivers.
36 */
Mark Brown77169772009-11-30 13:24:18 +000037int wm831x_isinkv_values[WM831X_ISINK_MAX_ISEL + 1] = {
Mark Brown698659d2009-07-27 14:45:57 +010038 2,
39 2,
40 3,
41 3,
42 4,
43 5,
44 6,
45 7,
46 8,
47 10,
48 11,
49 13,
50 16,
51 19,
52 23,
53 27,
54 32,
55 38,
56 45,
57 54,
58 64,
59 76,
60 91,
61 108,
62 128,
63 152,
64 181,
65 215,
66 256,
67 304,
68 362,
69 431,
70 512,
71 609,
72 724,
73 861,
74 1024,
75 1218,
76 1448,
77 1722,
78 2048,
79 2435,
80 2896,
81 3444,
82 4096,
83 4871,
84 5793,
85 6889,
86 8192,
87 9742,
88 11585,
89 13777,
90 16384,
91 19484,
92 23170,
93 27554,
94};
95EXPORT_SYMBOL_GPL(wm831x_isinkv_values);
Mark Brownd2bedfe2009-07-27 14:45:52 +010096
Mark Brownd2bedfe2009-07-27 14:45:52 +010097static int wm831x_reg_locked(struct wm831x *wm831x, unsigned short reg)
98{
99 if (!wm831x->locked)
100 return 0;
101
102 switch (reg) {
103 case WM831X_WATCHDOG:
104 case WM831X_DC4_CONTROL:
105 case WM831X_ON_PIN_CONTROL:
106 case WM831X_BACKUP_CHARGER_CONTROL:
107 case WM831X_CHARGER_CONTROL_1:
108 case WM831X_CHARGER_CONTROL_2:
109 return 1;
110
111 default:
112 return 0;
113 }
114}
115
116/**
117 * wm831x_reg_unlock: Unlock user keyed registers
118 *
119 * The WM831x has a user key preventing writes to particularly
120 * critical registers. This function locks those registers,
121 * allowing writes to them.
122 */
123void wm831x_reg_lock(struct wm831x *wm831x)
124{
125 int ret;
126
127 ret = wm831x_reg_write(wm831x, WM831X_SECURITY_KEY, 0);
128 if (ret == 0) {
129 dev_vdbg(wm831x->dev, "Registers locked\n");
130
131 mutex_lock(&wm831x->io_lock);
132 WARN_ON(wm831x->locked);
133 wm831x->locked = 1;
134 mutex_unlock(&wm831x->io_lock);
135 } else {
136 dev_err(wm831x->dev, "Failed to lock registers: %d\n", ret);
137 }
138
139}
140EXPORT_SYMBOL_GPL(wm831x_reg_lock);
141
142/**
143 * wm831x_reg_unlock: Unlock user keyed registers
144 *
145 * The WM831x has a user key preventing writes to particularly
146 * critical registers. This function locks those registers,
147 * preventing spurious writes.
148 */
149int wm831x_reg_unlock(struct wm831x *wm831x)
150{
151 int ret;
152
153 /* 0x9716 is the value required to unlock the registers */
154 ret = wm831x_reg_write(wm831x, WM831X_SECURITY_KEY, 0x9716);
155 if (ret == 0) {
156 dev_vdbg(wm831x->dev, "Registers unlocked\n");
157
158 mutex_lock(&wm831x->io_lock);
159 WARN_ON(!wm831x->locked);
160 wm831x->locked = 0;
161 mutex_unlock(&wm831x->io_lock);
162 }
163
164 return ret;
165}
166EXPORT_SYMBOL_GPL(wm831x_reg_unlock);
167
Mark Brown2e47fff2011-07-21 17:30:08 +0100168static bool wm831x_reg_readable(struct device *dev, unsigned int reg)
169{
170 switch (reg) {
171 case WM831X_RESET_ID:
172 case WM831X_REVISION:
173 case WM831X_PARENT_ID:
174 case WM831X_SYSVDD_CONTROL:
175 case WM831X_THERMAL_MONITORING:
176 case WM831X_POWER_STATE:
177 case WM831X_WATCHDOG:
178 case WM831X_ON_PIN_CONTROL:
179 case WM831X_RESET_CONTROL:
180 case WM831X_CONTROL_INTERFACE:
181 case WM831X_SECURITY_KEY:
182 case WM831X_SOFTWARE_SCRATCH:
183 case WM831X_OTP_CONTROL:
184 case WM831X_GPIO_LEVEL:
185 case WM831X_SYSTEM_STATUS:
186 case WM831X_ON_SOURCE:
187 case WM831X_OFF_SOURCE:
188 case WM831X_SYSTEM_INTERRUPTS:
189 case WM831X_INTERRUPT_STATUS_1:
190 case WM831X_INTERRUPT_STATUS_2:
191 case WM831X_INTERRUPT_STATUS_3:
192 case WM831X_INTERRUPT_STATUS_4:
193 case WM831X_INTERRUPT_STATUS_5:
194 case WM831X_IRQ_CONFIG:
195 case WM831X_SYSTEM_INTERRUPTS_MASK:
196 case WM831X_INTERRUPT_STATUS_1_MASK:
197 case WM831X_INTERRUPT_STATUS_2_MASK:
198 case WM831X_INTERRUPT_STATUS_3_MASK:
199 case WM831X_INTERRUPT_STATUS_4_MASK:
200 case WM831X_INTERRUPT_STATUS_5_MASK:
201 case WM831X_RTC_WRITE_COUNTER:
202 case WM831X_RTC_TIME_1:
203 case WM831X_RTC_TIME_2:
204 case WM831X_RTC_ALARM_1:
205 case WM831X_RTC_ALARM_2:
206 case WM831X_RTC_CONTROL:
207 case WM831X_RTC_TRIM:
208 case WM831X_TOUCH_CONTROL_1:
209 case WM831X_TOUCH_CONTROL_2:
210 case WM831X_TOUCH_DATA_X:
211 case WM831X_TOUCH_DATA_Y:
212 case WM831X_TOUCH_DATA_Z:
213 case WM831X_AUXADC_DATA:
214 case WM831X_AUXADC_CONTROL:
215 case WM831X_AUXADC_SOURCE:
216 case WM831X_COMPARATOR_CONTROL:
217 case WM831X_COMPARATOR_1:
218 case WM831X_COMPARATOR_2:
219 case WM831X_COMPARATOR_3:
220 case WM831X_COMPARATOR_4:
221 case WM831X_GPIO1_CONTROL:
222 case WM831X_GPIO2_CONTROL:
223 case WM831X_GPIO3_CONTROL:
224 case WM831X_GPIO4_CONTROL:
225 case WM831X_GPIO5_CONTROL:
226 case WM831X_GPIO6_CONTROL:
227 case WM831X_GPIO7_CONTROL:
228 case WM831X_GPIO8_CONTROL:
229 case WM831X_GPIO9_CONTROL:
230 case WM831X_GPIO10_CONTROL:
231 case WM831X_GPIO11_CONTROL:
232 case WM831X_GPIO12_CONTROL:
233 case WM831X_GPIO13_CONTROL:
234 case WM831X_GPIO14_CONTROL:
235 case WM831X_GPIO15_CONTROL:
236 case WM831X_GPIO16_CONTROL:
237 case WM831X_CHARGER_CONTROL_1:
238 case WM831X_CHARGER_CONTROL_2:
239 case WM831X_CHARGER_STATUS:
240 case WM831X_BACKUP_CHARGER_CONTROL:
241 case WM831X_STATUS_LED_1:
242 case WM831X_STATUS_LED_2:
243 case WM831X_CURRENT_SINK_1:
244 case WM831X_CURRENT_SINK_2:
245 case WM831X_DCDC_ENABLE:
246 case WM831X_LDO_ENABLE:
247 case WM831X_DCDC_STATUS:
248 case WM831X_LDO_STATUS:
249 case WM831X_DCDC_UV_STATUS:
250 case WM831X_LDO_UV_STATUS:
251 case WM831X_DC1_CONTROL_1:
252 case WM831X_DC1_CONTROL_2:
253 case WM831X_DC1_ON_CONFIG:
254 case WM831X_DC1_SLEEP_CONTROL:
255 case WM831X_DC1_DVS_CONTROL:
256 case WM831X_DC2_CONTROL_1:
257 case WM831X_DC2_CONTROL_2:
258 case WM831X_DC2_ON_CONFIG:
259 case WM831X_DC2_SLEEP_CONTROL:
260 case WM831X_DC2_DVS_CONTROL:
261 case WM831X_DC3_CONTROL_1:
262 case WM831X_DC3_CONTROL_2:
263 case WM831X_DC3_ON_CONFIG:
264 case WM831X_DC3_SLEEP_CONTROL:
265 case WM831X_DC4_CONTROL:
266 case WM831X_DC4_SLEEP_CONTROL:
267 case WM831X_EPE1_CONTROL:
268 case WM831X_EPE2_CONTROL:
269 case WM831X_LDO1_CONTROL:
270 case WM831X_LDO1_ON_CONTROL:
271 case WM831X_LDO1_SLEEP_CONTROL:
272 case WM831X_LDO2_CONTROL:
273 case WM831X_LDO2_ON_CONTROL:
274 case WM831X_LDO2_SLEEP_CONTROL:
275 case WM831X_LDO3_CONTROL:
276 case WM831X_LDO3_ON_CONTROL:
277 case WM831X_LDO3_SLEEP_CONTROL:
278 case WM831X_LDO4_CONTROL:
279 case WM831X_LDO4_ON_CONTROL:
280 case WM831X_LDO4_SLEEP_CONTROL:
281 case WM831X_LDO5_CONTROL:
282 case WM831X_LDO5_ON_CONTROL:
283 case WM831X_LDO5_SLEEP_CONTROL:
284 case WM831X_LDO6_CONTROL:
285 case WM831X_LDO6_ON_CONTROL:
286 case WM831X_LDO6_SLEEP_CONTROL:
287 case WM831X_LDO7_CONTROL:
288 case WM831X_LDO7_ON_CONTROL:
289 case WM831X_LDO7_SLEEP_CONTROL:
290 case WM831X_LDO8_CONTROL:
291 case WM831X_LDO8_ON_CONTROL:
292 case WM831X_LDO8_SLEEP_CONTROL:
293 case WM831X_LDO9_CONTROL:
294 case WM831X_LDO9_ON_CONTROL:
295 case WM831X_LDO9_SLEEP_CONTROL:
296 case WM831X_LDO10_CONTROL:
297 case WM831X_LDO10_ON_CONTROL:
298 case WM831X_LDO10_SLEEP_CONTROL:
299 case WM831X_LDO11_ON_CONTROL:
300 case WM831X_LDO11_SLEEP_CONTROL:
301 case WM831X_POWER_GOOD_SOURCE_1:
302 case WM831X_POWER_GOOD_SOURCE_2:
303 case WM831X_CLOCK_CONTROL_1:
304 case WM831X_CLOCK_CONTROL_2:
305 case WM831X_FLL_CONTROL_1:
306 case WM831X_FLL_CONTROL_2:
307 case WM831X_FLL_CONTROL_3:
308 case WM831X_FLL_CONTROL_4:
309 case WM831X_FLL_CONTROL_5:
310 case WM831X_UNIQUE_ID_1:
311 case WM831X_UNIQUE_ID_2:
312 case WM831X_UNIQUE_ID_3:
313 case WM831X_UNIQUE_ID_4:
314 case WM831X_UNIQUE_ID_5:
315 case WM831X_UNIQUE_ID_6:
316 case WM831X_UNIQUE_ID_7:
317 case WM831X_UNIQUE_ID_8:
318 case WM831X_FACTORY_OTP_ID:
319 case WM831X_FACTORY_OTP_1:
320 case WM831X_FACTORY_OTP_2:
321 case WM831X_FACTORY_OTP_3:
322 case WM831X_FACTORY_OTP_4:
323 case WM831X_FACTORY_OTP_5:
324 case WM831X_CUSTOMER_OTP_ID:
325 case WM831X_DC1_OTP_CONTROL:
326 case WM831X_DC2_OTP_CONTROL:
327 case WM831X_DC3_OTP_CONTROL:
328 case WM831X_LDO1_2_OTP_CONTROL:
329 case WM831X_LDO3_4_OTP_CONTROL:
330 case WM831X_LDO5_6_OTP_CONTROL:
331 case WM831X_LDO7_8_OTP_CONTROL:
332 case WM831X_LDO9_10_OTP_CONTROL:
333 case WM831X_LDO11_EPE_CONTROL:
334 case WM831X_GPIO1_OTP_CONTROL:
335 case WM831X_GPIO2_OTP_CONTROL:
336 case WM831X_GPIO3_OTP_CONTROL:
337 case WM831X_GPIO4_OTP_CONTROL:
338 case WM831X_GPIO5_OTP_CONTROL:
339 case WM831X_GPIO6_OTP_CONTROL:
340 case WM831X_DBE_CHECK_DATA:
341 return true;
342 default:
343 return false;
344 }
345}
346
347static bool wm831x_reg_writeable(struct device *dev, unsigned int reg)
348{
349 struct wm831x *wm831x = dev_get_drvdata(dev);
350
351 if (wm831x_reg_locked(wm831x, reg))
352 return false;
353
354 switch (reg) {
355 case WM831X_SYSVDD_CONTROL:
356 case WM831X_THERMAL_MONITORING:
357 case WM831X_POWER_STATE:
358 case WM831X_WATCHDOG:
359 case WM831X_ON_PIN_CONTROL:
360 case WM831X_RESET_CONTROL:
361 case WM831X_CONTROL_INTERFACE:
362 case WM831X_SECURITY_KEY:
363 case WM831X_SOFTWARE_SCRATCH:
364 case WM831X_OTP_CONTROL:
365 case WM831X_GPIO_LEVEL:
366 case WM831X_INTERRUPT_STATUS_1:
367 case WM831X_INTERRUPT_STATUS_2:
368 case WM831X_INTERRUPT_STATUS_3:
369 case WM831X_INTERRUPT_STATUS_4:
370 case WM831X_INTERRUPT_STATUS_5:
371 case WM831X_IRQ_CONFIG:
372 case WM831X_SYSTEM_INTERRUPTS_MASK:
373 case WM831X_INTERRUPT_STATUS_1_MASK:
374 case WM831X_INTERRUPT_STATUS_2_MASK:
375 case WM831X_INTERRUPT_STATUS_3_MASK:
376 case WM831X_INTERRUPT_STATUS_4_MASK:
377 case WM831X_INTERRUPT_STATUS_5_MASK:
378 case WM831X_RTC_TIME_1:
379 case WM831X_RTC_TIME_2:
380 case WM831X_RTC_ALARM_1:
381 case WM831X_RTC_ALARM_2:
382 case WM831X_RTC_CONTROL:
383 case WM831X_RTC_TRIM:
384 case WM831X_TOUCH_CONTROL_1:
385 case WM831X_TOUCH_CONTROL_2:
386 case WM831X_AUXADC_CONTROL:
387 case WM831X_AUXADC_SOURCE:
388 case WM831X_COMPARATOR_CONTROL:
389 case WM831X_COMPARATOR_1:
390 case WM831X_COMPARATOR_2:
391 case WM831X_COMPARATOR_3:
392 case WM831X_COMPARATOR_4:
393 case WM831X_GPIO1_CONTROL:
394 case WM831X_GPIO2_CONTROL:
395 case WM831X_GPIO3_CONTROL:
396 case WM831X_GPIO4_CONTROL:
397 case WM831X_GPIO5_CONTROL:
398 case WM831X_GPIO6_CONTROL:
399 case WM831X_GPIO7_CONTROL:
400 case WM831X_GPIO8_CONTROL:
401 case WM831X_GPIO9_CONTROL:
402 case WM831X_GPIO10_CONTROL:
403 case WM831X_GPIO11_CONTROL:
404 case WM831X_GPIO12_CONTROL:
405 case WM831X_GPIO13_CONTROL:
406 case WM831X_GPIO14_CONTROL:
407 case WM831X_GPIO15_CONTROL:
408 case WM831X_GPIO16_CONTROL:
409 case WM831X_CHARGER_CONTROL_1:
410 case WM831X_CHARGER_CONTROL_2:
411 case WM831X_CHARGER_STATUS:
412 case WM831X_BACKUP_CHARGER_CONTROL:
413 case WM831X_STATUS_LED_1:
414 case WM831X_STATUS_LED_2:
415 case WM831X_CURRENT_SINK_1:
416 case WM831X_CURRENT_SINK_2:
417 case WM831X_DCDC_ENABLE:
418 case WM831X_LDO_ENABLE:
419 case WM831X_DC1_CONTROL_1:
420 case WM831X_DC1_CONTROL_2:
421 case WM831X_DC1_ON_CONFIG:
422 case WM831X_DC1_SLEEP_CONTROL:
423 case WM831X_DC1_DVS_CONTROL:
424 case WM831X_DC2_CONTROL_1:
425 case WM831X_DC2_CONTROL_2:
426 case WM831X_DC2_ON_CONFIG:
427 case WM831X_DC2_SLEEP_CONTROL:
428 case WM831X_DC2_DVS_CONTROL:
429 case WM831X_DC3_CONTROL_1:
430 case WM831X_DC3_CONTROL_2:
431 case WM831X_DC3_ON_CONFIG:
432 case WM831X_DC3_SLEEP_CONTROL:
433 case WM831X_DC4_CONTROL:
434 case WM831X_DC4_SLEEP_CONTROL:
435 case WM831X_EPE1_CONTROL:
436 case WM831X_EPE2_CONTROL:
437 case WM831X_LDO1_CONTROL:
438 case WM831X_LDO1_ON_CONTROL:
439 case WM831X_LDO1_SLEEP_CONTROL:
440 case WM831X_LDO2_CONTROL:
441 case WM831X_LDO2_ON_CONTROL:
442 case WM831X_LDO2_SLEEP_CONTROL:
443 case WM831X_LDO3_CONTROL:
444 case WM831X_LDO3_ON_CONTROL:
445 case WM831X_LDO3_SLEEP_CONTROL:
446 case WM831X_LDO4_CONTROL:
447 case WM831X_LDO4_ON_CONTROL:
448 case WM831X_LDO4_SLEEP_CONTROL:
449 case WM831X_LDO5_CONTROL:
450 case WM831X_LDO5_ON_CONTROL:
451 case WM831X_LDO5_SLEEP_CONTROL:
452 case WM831X_LDO6_CONTROL:
453 case WM831X_LDO6_ON_CONTROL:
454 case WM831X_LDO6_SLEEP_CONTROL:
455 case WM831X_LDO7_CONTROL:
456 case WM831X_LDO7_ON_CONTROL:
457 case WM831X_LDO7_SLEEP_CONTROL:
458 case WM831X_LDO8_CONTROL:
459 case WM831X_LDO8_ON_CONTROL:
460 case WM831X_LDO8_SLEEP_CONTROL:
461 case WM831X_LDO9_CONTROL:
462 case WM831X_LDO9_ON_CONTROL:
463 case WM831X_LDO9_SLEEP_CONTROL:
464 case WM831X_LDO10_CONTROL:
465 case WM831X_LDO10_ON_CONTROL:
466 case WM831X_LDO10_SLEEP_CONTROL:
467 case WM831X_LDO11_ON_CONTROL:
468 case WM831X_LDO11_SLEEP_CONTROL:
469 case WM831X_POWER_GOOD_SOURCE_1:
470 case WM831X_POWER_GOOD_SOURCE_2:
471 case WM831X_CLOCK_CONTROL_1:
472 case WM831X_CLOCK_CONTROL_2:
473 case WM831X_FLL_CONTROL_1:
474 case WM831X_FLL_CONTROL_2:
475 case WM831X_FLL_CONTROL_3:
476 case WM831X_FLL_CONTROL_4:
477 case WM831X_FLL_CONTROL_5:
478 return true;
479 default:
480 return false;
481 }
482}
483
484static bool wm831x_reg_volatile(struct device *dev, unsigned int reg)
485{
486 switch (reg) {
487 case WM831X_SYSTEM_STATUS:
488 case WM831X_ON_SOURCE:
489 case WM831X_OFF_SOURCE:
490 case WM831X_GPIO_LEVEL:
491 case WM831X_SYSTEM_INTERRUPTS:
492 case WM831X_INTERRUPT_STATUS_1:
493 case WM831X_INTERRUPT_STATUS_2:
494 case WM831X_INTERRUPT_STATUS_3:
495 case WM831X_INTERRUPT_STATUS_4:
496 case WM831X_INTERRUPT_STATUS_5:
497 case WM831X_RTC_TIME_1:
498 case WM831X_RTC_TIME_2:
499 case WM831X_TOUCH_DATA_X:
500 case WM831X_TOUCH_DATA_Y:
501 case WM831X_TOUCH_DATA_Z:
502 case WM831X_AUXADC_DATA:
503 case WM831X_CHARGER_STATUS:
504 case WM831X_DCDC_STATUS:
505 case WM831X_LDO_STATUS:
506 case WM831X_DCDC_UV_STATUS:
507 case WM831X_LDO_UV_STATUS:
508 return true;
509 default:
510 return false;
511 }
512}
513
Mark Brownd2bedfe2009-07-27 14:45:52 +0100514/**
515 * wm831x_reg_read: Read a single WM831x register.
516 *
517 * @wm831x: Device to read from.
518 * @reg: Register to read.
519 */
520int wm831x_reg_read(struct wm831x *wm831x, unsigned short reg)
521{
Mark Brown1df59812011-06-10 19:28:10 +0100522 unsigned int val;
Mark Brownd2bedfe2009-07-27 14:45:52 +0100523 int ret;
524
Mark Brown1df59812011-06-10 19:28:10 +0100525 ret = regmap_read(wm831x->regmap, reg, &val);
Mark Brownd2bedfe2009-07-27 14:45:52 +0100526
527 if (ret < 0)
528 return ret;
529 else
530 return val;
531}
532EXPORT_SYMBOL_GPL(wm831x_reg_read);
533
534/**
535 * wm831x_bulk_read: Read multiple WM831x registers
536 *
537 * @wm831x: Device to read from
538 * @reg: First register
539 * @count: Number of registers
540 * @buf: Buffer to fill.
541 */
542int wm831x_bulk_read(struct wm831x *wm831x, unsigned short reg,
543 int count, u16 *buf)
544{
Mark Brown1df59812011-06-10 19:28:10 +0100545 return regmap_bulk_read(wm831x->regmap, reg, buf, count);
Mark Brownd2bedfe2009-07-27 14:45:52 +0100546}
547EXPORT_SYMBOL_GPL(wm831x_bulk_read);
548
549static int wm831x_write(struct wm831x *wm831x, unsigned short reg,
550 int bytes, void *src)
551{
552 u16 *buf = src;
Mark Brown1df59812011-06-10 19:28:10 +0100553 int i, ret;
Mark Brownd2bedfe2009-07-27 14:45:52 +0100554
555 BUG_ON(bytes % 2);
556 BUG_ON(bytes <= 0);
557
558 for (i = 0; i < bytes / 2; i++) {
559 if (wm831x_reg_locked(wm831x, reg))
560 return -EPERM;
561
562 dev_vdbg(wm831x->dev, "Write %04x to R%d(0x%x)\n",
563 buf[i], reg + i, reg + i);
Mark Brown1df59812011-06-10 19:28:10 +0100564 ret = regmap_write(wm831x->regmap, reg + i, buf[i]);
Mark Brown5391b5c2011-12-05 12:01:07 +0000565 if (ret != 0)
566 return ret;
Mark Brownd2bedfe2009-07-27 14:45:52 +0100567 }
568
Mark Brown1df59812011-06-10 19:28:10 +0100569 return 0;
Mark Brownd2bedfe2009-07-27 14:45:52 +0100570}
571
572/**
573 * wm831x_reg_write: Write a single WM831x register.
574 *
575 * @wm831x: Device to write to.
576 * @reg: Register to write to.
577 * @val: Value to write.
578 */
579int wm831x_reg_write(struct wm831x *wm831x, unsigned short reg,
580 unsigned short val)
581{
582 int ret;
583
584 mutex_lock(&wm831x->io_lock);
585
586 ret = wm831x_write(wm831x, reg, 2, &val);
587
588 mutex_unlock(&wm831x->io_lock);
589
590 return ret;
591}
592EXPORT_SYMBOL_GPL(wm831x_reg_write);
593
594/**
595 * wm831x_set_bits: Set the value of a bitfield in a WM831x register
596 *
597 * @wm831x: Device to write to.
598 * @reg: Register to write to.
599 * @mask: Mask of bits to set.
600 * @val: Value to set (unshifted)
601 */
602int wm831x_set_bits(struct wm831x *wm831x, unsigned short reg,
603 unsigned short mask, unsigned short val)
604{
605 int ret;
Mark Brownd2bedfe2009-07-27 14:45:52 +0100606
607 mutex_lock(&wm831x->io_lock);
608
Mark Brown1df59812011-06-10 19:28:10 +0100609 if (!wm831x_reg_locked(wm831x, reg))
610 ret = regmap_update_bits(wm831x->regmap, reg, mask, val);
611 else
612 ret = -EPERM;
Mark Brownd2bedfe2009-07-27 14:45:52 +0100613
Mark Brownd2bedfe2009-07-27 14:45:52 +0100614 mutex_unlock(&wm831x->io_lock);
615
616 return ret;
617}
618EXPORT_SYMBOL_GPL(wm831x_set_bits);
619
620static struct resource wm831x_dcdc1_resources[] = {
621 {
622 .start = WM831X_DC1_CONTROL_1,
623 .end = WM831X_DC1_DVS_CONTROL,
Mark Brown56560982012-08-07 19:42:47 +0100624 .flags = IORESOURCE_REG,
Mark Brownd2bedfe2009-07-27 14:45:52 +0100625 },
626 {
627 .name = "UV",
628 .start = WM831X_IRQ_UV_DC1,
629 .end = WM831X_IRQ_UV_DC1,
630 .flags = IORESOURCE_IRQ,
631 },
632 {
633 .name = "HC",
634 .start = WM831X_IRQ_HC_DC1,
635 .end = WM831X_IRQ_HC_DC1,
636 .flags = IORESOURCE_IRQ,
637 },
638};
639
640
641static struct resource wm831x_dcdc2_resources[] = {
642 {
643 .start = WM831X_DC2_CONTROL_1,
644 .end = WM831X_DC2_DVS_CONTROL,
Mark Brown56560982012-08-07 19:42:47 +0100645 .flags = IORESOURCE_REG,
Mark Brownd2bedfe2009-07-27 14:45:52 +0100646 },
647 {
648 .name = "UV",
649 .start = WM831X_IRQ_UV_DC2,
650 .end = WM831X_IRQ_UV_DC2,
651 .flags = IORESOURCE_IRQ,
652 },
653 {
654 .name = "HC",
655 .start = WM831X_IRQ_HC_DC2,
656 .end = WM831X_IRQ_HC_DC2,
657 .flags = IORESOURCE_IRQ,
658 },
659};
660
661static struct resource wm831x_dcdc3_resources[] = {
662 {
663 .start = WM831X_DC3_CONTROL_1,
664 .end = WM831X_DC3_SLEEP_CONTROL,
Mark Brown56560982012-08-07 19:42:47 +0100665 .flags = IORESOURCE_REG,
Mark Brownd2bedfe2009-07-27 14:45:52 +0100666 },
667 {
668 .name = "UV",
669 .start = WM831X_IRQ_UV_DC3,
670 .end = WM831X_IRQ_UV_DC3,
671 .flags = IORESOURCE_IRQ,
672 },
673};
674
675static struct resource wm831x_dcdc4_resources[] = {
676 {
677 .start = WM831X_DC4_CONTROL,
678 .end = WM831X_DC4_SLEEP_CONTROL,
Mark Brown56560982012-08-07 19:42:47 +0100679 .flags = IORESOURCE_REG,
Mark Brownd2bedfe2009-07-27 14:45:52 +0100680 },
681 {
682 .name = "UV",
683 .start = WM831X_IRQ_UV_DC4,
684 .end = WM831X_IRQ_UV_DC4,
685 .flags = IORESOURCE_IRQ,
686 },
687};
688
Mark Brownd4e0a892009-10-01 15:41:07 +0100689static struct resource wm8320_dcdc4_buck_resources[] = {
690 {
691 .start = WM831X_DC4_CONTROL,
692 .end = WM832X_DC4_SLEEP_CONTROL,
Mark Brown56560982012-08-07 19:42:47 +0100693 .flags = IORESOURCE_REG,
Mark Brownd4e0a892009-10-01 15:41:07 +0100694 },
695 {
696 .name = "UV",
697 .start = WM831X_IRQ_UV_DC4,
698 .end = WM831X_IRQ_UV_DC4,
699 .flags = IORESOURCE_IRQ,
700 },
701};
702
Mark Brownd2bedfe2009-07-27 14:45:52 +0100703static struct resource wm831x_gpio_resources[] = {
704 {
705 .start = WM831X_IRQ_GPIO_1,
706 .end = WM831X_IRQ_GPIO_16,
707 .flags = IORESOURCE_IRQ,
708 },
709};
710
711static struct resource wm831x_isink1_resources[] = {
712 {
713 .start = WM831X_CURRENT_SINK_1,
714 .end = WM831X_CURRENT_SINK_1,
Mark Brown56560982012-08-07 19:42:47 +0100715 .flags = IORESOURCE_REG,
Mark Brownd2bedfe2009-07-27 14:45:52 +0100716 },
717 {
718 .start = WM831X_IRQ_CS1,
719 .end = WM831X_IRQ_CS1,
720 .flags = IORESOURCE_IRQ,
721 },
722};
723
724static struct resource wm831x_isink2_resources[] = {
725 {
726 .start = WM831X_CURRENT_SINK_2,
727 .end = WM831X_CURRENT_SINK_2,
Mark Brown56560982012-08-07 19:42:47 +0100728 .flags = IORESOURCE_REG,
Mark Brownd2bedfe2009-07-27 14:45:52 +0100729 },
730 {
731 .start = WM831X_IRQ_CS2,
732 .end = WM831X_IRQ_CS2,
733 .flags = IORESOURCE_IRQ,
734 },
735};
736
737static struct resource wm831x_ldo1_resources[] = {
738 {
739 .start = WM831X_LDO1_CONTROL,
740 .end = WM831X_LDO1_SLEEP_CONTROL,
Mark Brown56560982012-08-07 19:42:47 +0100741 .flags = IORESOURCE_REG,
Mark Brownd2bedfe2009-07-27 14:45:52 +0100742 },
743 {
744 .name = "UV",
745 .start = WM831X_IRQ_UV_LDO1,
746 .end = WM831X_IRQ_UV_LDO1,
747 .flags = IORESOURCE_IRQ,
748 },
749};
750
751static struct resource wm831x_ldo2_resources[] = {
752 {
753 .start = WM831X_LDO2_CONTROL,
754 .end = WM831X_LDO2_SLEEP_CONTROL,
Mark Brown56560982012-08-07 19:42:47 +0100755 .flags = IORESOURCE_REG,
Mark Brownd2bedfe2009-07-27 14:45:52 +0100756 },
757 {
758 .name = "UV",
759 .start = WM831X_IRQ_UV_LDO2,
760 .end = WM831X_IRQ_UV_LDO2,
761 .flags = IORESOURCE_IRQ,
762 },
763};
764
765static struct resource wm831x_ldo3_resources[] = {
766 {
767 .start = WM831X_LDO3_CONTROL,
768 .end = WM831X_LDO3_SLEEP_CONTROL,
Mark Brown56560982012-08-07 19:42:47 +0100769 .flags = IORESOURCE_REG,
Mark Brownd2bedfe2009-07-27 14:45:52 +0100770 },
771 {
772 .name = "UV",
773 .start = WM831X_IRQ_UV_LDO3,
774 .end = WM831X_IRQ_UV_LDO3,
775 .flags = IORESOURCE_IRQ,
776 },
777};
778
779static struct resource wm831x_ldo4_resources[] = {
780 {
781 .start = WM831X_LDO4_CONTROL,
782 .end = WM831X_LDO4_SLEEP_CONTROL,
Mark Brown56560982012-08-07 19:42:47 +0100783 .flags = IORESOURCE_REG,
Mark Brownd2bedfe2009-07-27 14:45:52 +0100784 },
785 {
786 .name = "UV",
787 .start = WM831X_IRQ_UV_LDO4,
788 .end = WM831X_IRQ_UV_LDO4,
789 .flags = IORESOURCE_IRQ,
790 },
791};
792
793static struct resource wm831x_ldo5_resources[] = {
794 {
795 .start = WM831X_LDO5_CONTROL,
796 .end = WM831X_LDO5_SLEEP_CONTROL,
Mark Brown56560982012-08-07 19:42:47 +0100797 .flags = IORESOURCE_REG,
Mark Brownd2bedfe2009-07-27 14:45:52 +0100798 },
799 {
800 .name = "UV",
801 .start = WM831X_IRQ_UV_LDO5,
802 .end = WM831X_IRQ_UV_LDO5,
803 .flags = IORESOURCE_IRQ,
804 },
805};
806
807static struct resource wm831x_ldo6_resources[] = {
808 {
809 .start = WM831X_LDO6_CONTROL,
810 .end = WM831X_LDO6_SLEEP_CONTROL,
Mark Brown56560982012-08-07 19:42:47 +0100811 .flags = IORESOURCE_REG,
Mark Brownd2bedfe2009-07-27 14:45:52 +0100812 },
813 {
814 .name = "UV",
815 .start = WM831X_IRQ_UV_LDO6,
816 .end = WM831X_IRQ_UV_LDO6,
817 .flags = IORESOURCE_IRQ,
818 },
819};
820
821static struct resource wm831x_ldo7_resources[] = {
822 {
823 .start = WM831X_LDO7_CONTROL,
824 .end = WM831X_LDO7_SLEEP_CONTROL,
Mark Brown56560982012-08-07 19:42:47 +0100825 .flags = IORESOURCE_REG,
Mark Brownd2bedfe2009-07-27 14:45:52 +0100826 },
827 {
828 .name = "UV",
829 .start = WM831X_IRQ_UV_LDO7,
830 .end = WM831X_IRQ_UV_LDO7,
831 .flags = IORESOURCE_IRQ,
832 },
833};
834
835static struct resource wm831x_ldo8_resources[] = {
836 {
837 .start = WM831X_LDO8_CONTROL,
838 .end = WM831X_LDO8_SLEEP_CONTROL,
Mark Brown56560982012-08-07 19:42:47 +0100839 .flags = IORESOURCE_REG,
Mark Brownd2bedfe2009-07-27 14:45:52 +0100840 },
841 {
842 .name = "UV",
843 .start = WM831X_IRQ_UV_LDO8,
844 .end = WM831X_IRQ_UV_LDO8,
845 .flags = IORESOURCE_IRQ,
846 },
847};
848
849static struct resource wm831x_ldo9_resources[] = {
850 {
851 .start = WM831X_LDO9_CONTROL,
852 .end = WM831X_LDO9_SLEEP_CONTROL,
Mark Brown56560982012-08-07 19:42:47 +0100853 .flags = IORESOURCE_REG,
Mark Brownd2bedfe2009-07-27 14:45:52 +0100854 },
855 {
856 .name = "UV",
857 .start = WM831X_IRQ_UV_LDO9,
858 .end = WM831X_IRQ_UV_LDO9,
859 .flags = IORESOURCE_IRQ,
860 },
861};
862
863static struct resource wm831x_ldo10_resources[] = {
864 {
865 .start = WM831X_LDO10_CONTROL,
866 .end = WM831X_LDO10_SLEEP_CONTROL,
Mark Brown56560982012-08-07 19:42:47 +0100867 .flags = IORESOURCE_REG,
Mark Brownd2bedfe2009-07-27 14:45:52 +0100868 },
869 {
870 .name = "UV",
871 .start = WM831X_IRQ_UV_LDO10,
872 .end = WM831X_IRQ_UV_LDO10,
873 .flags = IORESOURCE_IRQ,
874 },
875};
876
877static struct resource wm831x_ldo11_resources[] = {
878 {
879 .start = WM831X_LDO11_ON_CONTROL,
880 .end = WM831X_LDO11_SLEEP_CONTROL,
Mark Brown56560982012-08-07 19:42:47 +0100881 .flags = IORESOURCE_REG,
Mark Brownd2bedfe2009-07-27 14:45:52 +0100882 },
883};
884
885static struct resource wm831x_on_resources[] = {
886 {
887 .start = WM831X_IRQ_ON,
888 .end = WM831X_IRQ_ON,
889 .flags = IORESOURCE_IRQ,
890 },
891};
892
893
894static struct resource wm831x_power_resources[] = {
895 {
896 .name = "SYSLO",
897 .start = WM831X_IRQ_PPM_SYSLO,
898 .end = WM831X_IRQ_PPM_SYSLO,
899 .flags = IORESOURCE_IRQ,
900 },
901 {
902 .name = "PWR SRC",
903 .start = WM831X_IRQ_PPM_PWR_SRC,
904 .end = WM831X_IRQ_PPM_PWR_SRC,
905 .flags = IORESOURCE_IRQ,
906 },
907 {
908 .name = "USB CURR",
909 .start = WM831X_IRQ_PPM_USB_CURR,
910 .end = WM831X_IRQ_PPM_USB_CURR,
911 .flags = IORESOURCE_IRQ,
912 },
913 {
914 .name = "BATT HOT",
915 .start = WM831X_IRQ_CHG_BATT_HOT,
916 .end = WM831X_IRQ_CHG_BATT_HOT,
917 .flags = IORESOURCE_IRQ,
918 },
919 {
920 .name = "BATT COLD",
921 .start = WM831X_IRQ_CHG_BATT_COLD,
922 .end = WM831X_IRQ_CHG_BATT_COLD,
923 .flags = IORESOURCE_IRQ,
924 },
925 {
926 .name = "BATT FAIL",
927 .start = WM831X_IRQ_CHG_BATT_FAIL,
928 .end = WM831X_IRQ_CHG_BATT_FAIL,
929 .flags = IORESOURCE_IRQ,
930 },
931 {
932 .name = "OV",
933 .start = WM831X_IRQ_CHG_OV,
934 .end = WM831X_IRQ_CHG_OV,
935 .flags = IORESOURCE_IRQ,
936 },
937 {
938 .name = "END",
939 .start = WM831X_IRQ_CHG_END,
940 .end = WM831X_IRQ_CHG_END,
941 .flags = IORESOURCE_IRQ,
942 },
943 {
944 .name = "TO",
945 .start = WM831X_IRQ_CHG_TO,
946 .end = WM831X_IRQ_CHG_TO,
947 .flags = IORESOURCE_IRQ,
948 },
949 {
950 .name = "MODE",
951 .start = WM831X_IRQ_CHG_MODE,
952 .end = WM831X_IRQ_CHG_MODE,
953 .flags = IORESOURCE_IRQ,
954 },
955 {
956 .name = "START",
957 .start = WM831X_IRQ_CHG_START,
958 .end = WM831X_IRQ_CHG_START,
959 .flags = IORESOURCE_IRQ,
960 },
961};
962
963static struct resource wm831x_rtc_resources[] = {
964 {
965 .name = "PER",
966 .start = WM831X_IRQ_RTC_PER,
967 .end = WM831X_IRQ_RTC_PER,
968 .flags = IORESOURCE_IRQ,
969 },
970 {
971 .name = "ALM",
972 .start = WM831X_IRQ_RTC_ALM,
973 .end = WM831X_IRQ_RTC_ALM,
974 .flags = IORESOURCE_IRQ,
975 },
976};
977
978static struct resource wm831x_status1_resources[] = {
979 {
980 .start = WM831X_STATUS_LED_1,
981 .end = WM831X_STATUS_LED_1,
Mark Brown56560982012-08-07 19:42:47 +0100982 .flags = IORESOURCE_REG,
Mark Brownd2bedfe2009-07-27 14:45:52 +0100983 },
984};
985
986static struct resource wm831x_status2_resources[] = {
987 {
988 .start = WM831X_STATUS_LED_2,
989 .end = WM831X_STATUS_LED_2,
Mark Brown56560982012-08-07 19:42:47 +0100990 .flags = IORESOURCE_REG,
Mark Brownd2bedfe2009-07-27 14:45:52 +0100991 },
992};
993
994static struct resource wm831x_touch_resources[] = {
995 {
996 .name = "TCHPD",
997 .start = WM831X_IRQ_TCHPD,
998 .end = WM831X_IRQ_TCHPD,
999 .flags = IORESOURCE_IRQ,
1000 },
1001 {
1002 .name = "TCHDATA",
1003 .start = WM831X_IRQ_TCHDATA,
1004 .end = WM831X_IRQ_TCHDATA,
1005 .flags = IORESOURCE_IRQ,
1006 },
1007};
1008
1009static struct resource wm831x_wdt_resources[] = {
1010 {
1011 .start = WM831X_IRQ_WDOG_TO,
1012 .end = WM831X_IRQ_WDOG_TO,
1013 .flags = IORESOURCE_IRQ,
1014 },
1015};
1016
Geert Uytterhoevenad59de42013-11-18 14:33:04 +01001017static const struct mfd_cell wm8310_devs[] = {
Mark Brownd2bedfe2009-07-27 14:45:52 +01001018 {
Mark Brownc26964e2009-10-01 15:41:06 +01001019 .name = "wm831x-backup",
1020 },
1021 {
Mark Brownd2bedfe2009-07-27 14:45:52 +01001022 .name = "wm831x-buckv",
1023 .id = 1,
1024 .num_resources = ARRAY_SIZE(wm831x_dcdc1_resources),
1025 .resources = wm831x_dcdc1_resources,
1026 },
1027 {
1028 .name = "wm831x-buckv",
1029 .id = 2,
1030 .num_resources = ARRAY_SIZE(wm831x_dcdc2_resources),
1031 .resources = wm831x_dcdc2_resources,
1032 },
1033 {
1034 .name = "wm831x-buckp",
1035 .id = 3,
1036 .num_resources = ARRAY_SIZE(wm831x_dcdc3_resources),
1037 .resources = wm831x_dcdc3_resources,
1038 },
1039 {
1040 .name = "wm831x-boostp",
1041 .id = 4,
1042 .num_resources = ARRAY_SIZE(wm831x_dcdc4_resources),
1043 .resources = wm831x_dcdc4_resources,
1044 },
1045 {
Mark Browna5e06782011-06-24 12:17:07 +01001046 .name = "wm831x-clk",
1047 },
1048 {
Mark Brownd2bedfe2009-07-27 14:45:52 +01001049 .name = "wm831x-epe",
1050 .id = 1,
1051 },
1052 {
1053 .name = "wm831x-epe",
1054 .id = 2,
1055 },
1056 {
1057 .name = "wm831x-gpio",
1058 .num_resources = ARRAY_SIZE(wm831x_gpio_resources),
1059 .resources = wm831x_gpio_resources,
1060 },
1061 {
1062 .name = "wm831x-hwmon",
1063 },
1064 {
1065 .name = "wm831x-isink",
1066 .id = 1,
1067 .num_resources = ARRAY_SIZE(wm831x_isink1_resources),
1068 .resources = wm831x_isink1_resources,
1069 },
1070 {
1071 .name = "wm831x-isink",
1072 .id = 2,
1073 .num_resources = ARRAY_SIZE(wm831x_isink2_resources),
1074 .resources = wm831x_isink2_resources,
1075 },
1076 {
1077 .name = "wm831x-ldo",
1078 .id = 1,
1079 .num_resources = ARRAY_SIZE(wm831x_ldo1_resources),
1080 .resources = wm831x_ldo1_resources,
1081 },
1082 {
1083 .name = "wm831x-ldo",
1084 .id = 2,
1085 .num_resources = ARRAY_SIZE(wm831x_ldo2_resources),
1086 .resources = wm831x_ldo2_resources,
1087 },
1088 {
1089 .name = "wm831x-ldo",
1090 .id = 3,
1091 .num_resources = ARRAY_SIZE(wm831x_ldo3_resources),
1092 .resources = wm831x_ldo3_resources,
1093 },
1094 {
1095 .name = "wm831x-ldo",
1096 .id = 4,
1097 .num_resources = ARRAY_SIZE(wm831x_ldo4_resources),
1098 .resources = wm831x_ldo4_resources,
1099 },
1100 {
1101 .name = "wm831x-ldo",
1102 .id = 5,
1103 .num_resources = ARRAY_SIZE(wm831x_ldo5_resources),
1104 .resources = wm831x_ldo5_resources,
1105 },
1106 {
1107 .name = "wm831x-ldo",
1108 .id = 6,
1109 .num_resources = ARRAY_SIZE(wm831x_ldo6_resources),
1110 .resources = wm831x_ldo6_resources,
1111 },
1112 {
1113 .name = "wm831x-aldo",
1114 .id = 7,
1115 .num_resources = ARRAY_SIZE(wm831x_ldo7_resources),
1116 .resources = wm831x_ldo7_resources,
1117 },
1118 {
1119 .name = "wm831x-aldo",
1120 .id = 8,
1121 .num_resources = ARRAY_SIZE(wm831x_ldo8_resources),
1122 .resources = wm831x_ldo8_resources,
1123 },
1124 {
1125 .name = "wm831x-aldo",
1126 .id = 9,
1127 .num_resources = ARRAY_SIZE(wm831x_ldo9_resources),
1128 .resources = wm831x_ldo9_resources,
1129 },
1130 {
1131 .name = "wm831x-aldo",
1132 .id = 10,
1133 .num_resources = ARRAY_SIZE(wm831x_ldo10_resources),
1134 .resources = wm831x_ldo10_resources,
1135 },
1136 {
1137 .name = "wm831x-alive-ldo",
1138 .id = 11,
1139 .num_resources = ARRAY_SIZE(wm831x_ldo11_resources),
1140 .resources = wm831x_ldo11_resources,
1141 },
1142 {
1143 .name = "wm831x-on",
1144 .num_resources = ARRAY_SIZE(wm831x_on_resources),
1145 .resources = wm831x_on_resources,
1146 },
1147 {
1148 .name = "wm831x-power",
1149 .num_resources = ARRAY_SIZE(wm831x_power_resources),
1150 .resources = wm831x_power_resources,
1151 },
1152 {
Mark Brownd2bedfe2009-07-27 14:45:52 +01001153 .name = "wm831x-status",
1154 .id = 1,
1155 .num_resources = ARRAY_SIZE(wm831x_status1_resources),
1156 .resources = wm831x_status1_resources,
1157 },
1158 {
1159 .name = "wm831x-status",
1160 .id = 2,
1161 .num_resources = ARRAY_SIZE(wm831x_status2_resources),
1162 .resources = wm831x_status2_resources,
1163 },
1164 {
1165 .name = "wm831x-watchdog",
1166 .num_resources = ARRAY_SIZE(wm831x_wdt_resources),
1167 .resources = wm831x_wdt_resources,
1168 },
1169};
1170
Geert Uytterhoevenad59de42013-11-18 14:33:04 +01001171static const struct mfd_cell wm8311_devs[] = {
Mark Brownd2bedfe2009-07-27 14:45:52 +01001172 {
Mark Brownc26964e2009-10-01 15:41:06 +01001173 .name = "wm831x-backup",
1174 },
1175 {
Mark Brownd2bedfe2009-07-27 14:45:52 +01001176 .name = "wm831x-buckv",
1177 .id = 1,
1178 .num_resources = ARRAY_SIZE(wm831x_dcdc1_resources),
1179 .resources = wm831x_dcdc1_resources,
1180 },
1181 {
1182 .name = "wm831x-buckv",
1183 .id = 2,
1184 .num_resources = ARRAY_SIZE(wm831x_dcdc2_resources),
1185 .resources = wm831x_dcdc2_resources,
1186 },
1187 {
1188 .name = "wm831x-buckp",
1189 .id = 3,
1190 .num_resources = ARRAY_SIZE(wm831x_dcdc3_resources),
1191 .resources = wm831x_dcdc3_resources,
1192 },
1193 {
1194 .name = "wm831x-boostp",
1195 .id = 4,
1196 .num_resources = ARRAY_SIZE(wm831x_dcdc4_resources),
1197 .resources = wm831x_dcdc4_resources,
1198 },
1199 {
Mark Browna5e06782011-06-24 12:17:07 +01001200 .name = "wm831x-clk",
1201 },
1202 {
Mark Brownd2bedfe2009-07-27 14:45:52 +01001203 .name = "wm831x-epe",
1204 .id = 1,
1205 },
1206 {
1207 .name = "wm831x-epe",
1208 .id = 2,
1209 },
1210 {
1211 .name = "wm831x-gpio",
1212 .num_resources = ARRAY_SIZE(wm831x_gpio_resources),
1213 .resources = wm831x_gpio_resources,
1214 },
1215 {
1216 .name = "wm831x-hwmon",
1217 },
1218 {
1219 .name = "wm831x-isink",
1220 .id = 1,
1221 .num_resources = ARRAY_SIZE(wm831x_isink1_resources),
1222 .resources = wm831x_isink1_resources,
1223 },
1224 {
1225 .name = "wm831x-isink",
1226 .id = 2,
1227 .num_resources = ARRAY_SIZE(wm831x_isink2_resources),
1228 .resources = wm831x_isink2_resources,
1229 },
1230 {
1231 .name = "wm831x-ldo",
1232 .id = 1,
1233 .num_resources = ARRAY_SIZE(wm831x_ldo1_resources),
1234 .resources = wm831x_ldo1_resources,
1235 },
1236 {
1237 .name = "wm831x-ldo",
1238 .id = 2,
1239 .num_resources = ARRAY_SIZE(wm831x_ldo2_resources),
1240 .resources = wm831x_ldo2_resources,
1241 },
1242 {
1243 .name = "wm831x-ldo",
1244 .id = 3,
1245 .num_resources = ARRAY_SIZE(wm831x_ldo3_resources),
1246 .resources = wm831x_ldo3_resources,
1247 },
1248 {
1249 .name = "wm831x-ldo",
1250 .id = 4,
1251 .num_resources = ARRAY_SIZE(wm831x_ldo4_resources),
1252 .resources = wm831x_ldo4_resources,
1253 },
1254 {
1255 .name = "wm831x-ldo",
1256 .id = 5,
1257 .num_resources = ARRAY_SIZE(wm831x_ldo5_resources),
1258 .resources = wm831x_ldo5_resources,
1259 },
1260 {
1261 .name = "wm831x-aldo",
1262 .id = 7,
1263 .num_resources = ARRAY_SIZE(wm831x_ldo7_resources),
1264 .resources = wm831x_ldo7_resources,
1265 },
1266 {
1267 .name = "wm831x-alive-ldo",
1268 .id = 11,
1269 .num_resources = ARRAY_SIZE(wm831x_ldo11_resources),
1270 .resources = wm831x_ldo11_resources,
1271 },
1272 {
1273 .name = "wm831x-on",
1274 .num_resources = ARRAY_SIZE(wm831x_on_resources),
1275 .resources = wm831x_on_resources,
1276 },
1277 {
1278 .name = "wm831x-power",
1279 .num_resources = ARRAY_SIZE(wm831x_power_resources),
1280 .resources = wm831x_power_resources,
1281 },
1282 {
Mark Brownd2bedfe2009-07-27 14:45:52 +01001283 .name = "wm831x-status",
1284 .id = 1,
1285 .num_resources = ARRAY_SIZE(wm831x_status1_resources),
1286 .resources = wm831x_status1_resources,
1287 },
1288 {
1289 .name = "wm831x-status",
1290 .id = 2,
1291 .num_resources = ARRAY_SIZE(wm831x_status2_resources),
1292 .resources = wm831x_status2_resources,
1293 },
1294 {
Mark Brownd2bedfe2009-07-27 14:45:52 +01001295 .name = "wm831x-watchdog",
1296 .num_resources = ARRAY_SIZE(wm831x_wdt_resources),
1297 .resources = wm831x_wdt_resources,
1298 },
1299};
1300
Geert Uytterhoevenad59de42013-11-18 14:33:04 +01001301static const struct mfd_cell wm8312_devs[] = {
Mark Brownd2bedfe2009-07-27 14:45:52 +01001302 {
Mark Brownc26964e2009-10-01 15:41:06 +01001303 .name = "wm831x-backup",
1304 },
1305 {
Mark Brownd2bedfe2009-07-27 14:45:52 +01001306 .name = "wm831x-buckv",
1307 .id = 1,
1308 .num_resources = ARRAY_SIZE(wm831x_dcdc1_resources),
1309 .resources = wm831x_dcdc1_resources,
1310 },
1311 {
1312 .name = "wm831x-buckv",
1313 .id = 2,
1314 .num_resources = ARRAY_SIZE(wm831x_dcdc2_resources),
1315 .resources = wm831x_dcdc2_resources,
1316 },
1317 {
1318 .name = "wm831x-buckp",
1319 .id = 3,
1320 .num_resources = ARRAY_SIZE(wm831x_dcdc3_resources),
1321 .resources = wm831x_dcdc3_resources,
1322 },
1323 {
1324 .name = "wm831x-boostp",
1325 .id = 4,
1326 .num_resources = ARRAY_SIZE(wm831x_dcdc4_resources),
1327 .resources = wm831x_dcdc4_resources,
1328 },
1329 {
Mark Browna5e06782011-06-24 12:17:07 +01001330 .name = "wm831x-clk",
1331 },
1332 {
Mark Brownd2bedfe2009-07-27 14:45:52 +01001333 .name = "wm831x-epe",
1334 .id = 1,
1335 },
1336 {
1337 .name = "wm831x-epe",
1338 .id = 2,
1339 },
1340 {
1341 .name = "wm831x-gpio",
1342 .num_resources = ARRAY_SIZE(wm831x_gpio_resources),
1343 .resources = wm831x_gpio_resources,
1344 },
1345 {
1346 .name = "wm831x-hwmon",
1347 },
1348 {
1349 .name = "wm831x-isink",
1350 .id = 1,
1351 .num_resources = ARRAY_SIZE(wm831x_isink1_resources),
1352 .resources = wm831x_isink1_resources,
1353 },
1354 {
1355 .name = "wm831x-isink",
1356 .id = 2,
1357 .num_resources = ARRAY_SIZE(wm831x_isink2_resources),
1358 .resources = wm831x_isink2_resources,
1359 },
1360 {
1361 .name = "wm831x-ldo",
1362 .id = 1,
1363 .num_resources = ARRAY_SIZE(wm831x_ldo1_resources),
1364 .resources = wm831x_ldo1_resources,
1365 },
1366 {
1367 .name = "wm831x-ldo",
1368 .id = 2,
1369 .num_resources = ARRAY_SIZE(wm831x_ldo2_resources),
1370 .resources = wm831x_ldo2_resources,
1371 },
1372 {
1373 .name = "wm831x-ldo",
1374 .id = 3,
1375 .num_resources = ARRAY_SIZE(wm831x_ldo3_resources),
1376 .resources = wm831x_ldo3_resources,
1377 },
1378 {
1379 .name = "wm831x-ldo",
1380 .id = 4,
1381 .num_resources = ARRAY_SIZE(wm831x_ldo4_resources),
1382 .resources = wm831x_ldo4_resources,
1383 },
1384 {
1385 .name = "wm831x-ldo",
1386 .id = 5,
1387 .num_resources = ARRAY_SIZE(wm831x_ldo5_resources),
1388 .resources = wm831x_ldo5_resources,
1389 },
1390 {
1391 .name = "wm831x-ldo",
1392 .id = 6,
1393 .num_resources = ARRAY_SIZE(wm831x_ldo6_resources),
1394 .resources = wm831x_ldo6_resources,
1395 },
1396 {
1397 .name = "wm831x-aldo",
1398 .id = 7,
1399 .num_resources = ARRAY_SIZE(wm831x_ldo7_resources),
1400 .resources = wm831x_ldo7_resources,
1401 },
1402 {
1403 .name = "wm831x-aldo",
1404 .id = 8,
1405 .num_resources = ARRAY_SIZE(wm831x_ldo8_resources),
1406 .resources = wm831x_ldo8_resources,
1407 },
1408 {
1409 .name = "wm831x-aldo",
1410 .id = 9,
1411 .num_resources = ARRAY_SIZE(wm831x_ldo9_resources),
1412 .resources = wm831x_ldo9_resources,
1413 },
1414 {
1415 .name = "wm831x-aldo",
1416 .id = 10,
1417 .num_resources = ARRAY_SIZE(wm831x_ldo10_resources),
1418 .resources = wm831x_ldo10_resources,
1419 },
1420 {
1421 .name = "wm831x-alive-ldo",
1422 .id = 11,
1423 .num_resources = ARRAY_SIZE(wm831x_ldo11_resources),
1424 .resources = wm831x_ldo11_resources,
1425 },
1426 {
1427 .name = "wm831x-on",
1428 .num_resources = ARRAY_SIZE(wm831x_on_resources),
1429 .resources = wm831x_on_resources,
1430 },
1431 {
1432 .name = "wm831x-power",
1433 .num_resources = ARRAY_SIZE(wm831x_power_resources),
1434 .resources = wm831x_power_resources,
1435 },
1436 {
Mark Brownd2bedfe2009-07-27 14:45:52 +01001437 .name = "wm831x-status",
1438 .id = 1,
1439 .num_resources = ARRAY_SIZE(wm831x_status1_resources),
1440 .resources = wm831x_status1_resources,
1441 },
1442 {
1443 .name = "wm831x-status",
1444 .id = 2,
1445 .num_resources = ARRAY_SIZE(wm831x_status2_resources),
1446 .resources = wm831x_status2_resources,
1447 },
1448 {
Mark Brownd2bedfe2009-07-27 14:45:52 +01001449 .name = "wm831x-watchdog",
1450 .num_resources = ARRAY_SIZE(wm831x_wdt_resources),
1451 .resources = wm831x_wdt_resources,
1452 },
1453};
1454
Geert Uytterhoevenad59de42013-11-18 14:33:04 +01001455static const struct mfd_cell wm8320_devs[] = {
Mark Brownd4e0a892009-10-01 15:41:07 +01001456 {
1457 .name = "wm831x-backup",
1458 },
1459 {
1460 .name = "wm831x-buckv",
1461 .id = 1,
1462 .num_resources = ARRAY_SIZE(wm831x_dcdc1_resources),
1463 .resources = wm831x_dcdc1_resources,
1464 },
1465 {
1466 .name = "wm831x-buckv",
1467 .id = 2,
1468 .num_resources = ARRAY_SIZE(wm831x_dcdc2_resources),
1469 .resources = wm831x_dcdc2_resources,
1470 },
1471 {
1472 .name = "wm831x-buckp",
1473 .id = 3,
1474 .num_resources = ARRAY_SIZE(wm831x_dcdc3_resources),
1475 .resources = wm831x_dcdc3_resources,
1476 },
1477 {
1478 .name = "wm831x-buckp",
1479 .id = 4,
1480 .num_resources = ARRAY_SIZE(wm8320_dcdc4_buck_resources),
1481 .resources = wm8320_dcdc4_buck_resources,
1482 },
1483 {
Mark Browna5e06782011-06-24 12:17:07 +01001484 .name = "wm831x-clk",
1485 },
1486 {
Mark Brownd4e0a892009-10-01 15:41:07 +01001487 .name = "wm831x-gpio",
1488 .num_resources = ARRAY_SIZE(wm831x_gpio_resources),
1489 .resources = wm831x_gpio_resources,
1490 },
1491 {
1492 .name = "wm831x-hwmon",
1493 },
1494 {
1495 .name = "wm831x-ldo",
1496 .id = 1,
1497 .num_resources = ARRAY_SIZE(wm831x_ldo1_resources),
1498 .resources = wm831x_ldo1_resources,
1499 },
1500 {
1501 .name = "wm831x-ldo",
1502 .id = 2,
1503 .num_resources = ARRAY_SIZE(wm831x_ldo2_resources),
1504 .resources = wm831x_ldo2_resources,
1505 },
1506 {
1507 .name = "wm831x-ldo",
1508 .id = 3,
1509 .num_resources = ARRAY_SIZE(wm831x_ldo3_resources),
1510 .resources = wm831x_ldo3_resources,
1511 },
1512 {
1513 .name = "wm831x-ldo",
1514 .id = 4,
1515 .num_resources = ARRAY_SIZE(wm831x_ldo4_resources),
1516 .resources = wm831x_ldo4_resources,
1517 },
1518 {
1519 .name = "wm831x-ldo",
1520 .id = 5,
1521 .num_resources = ARRAY_SIZE(wm831x_ldo5_resources),
1522 .resources = wm831x_ldo5_resources,
1523 },
1524 {
1525 .name = "wm831x-ldo",
1526 .id = 6,
1527 .num_resources = ARRAY_SIZE(wm831x_ldo6_resources),
1528 .resources = wm831x_ldo6_resources,
1529 },
1530 {
1531 .name = "wm831x-aldo",
1532 .id = 7,
1533 .num_resources = ARRAY_SIZE(wm831x_ldo7_resources),
1534 .resources = wm831x_ldo7_resources,
1535 },
1536 {
1537 .name = "wm831x-aldo",
1538 .id = 8,
1539 .num_resources = ARRAY_SIZE(wm831x_ldo8_resources),
1540 .resources = wm831x_ldo8_resources,
1541 },
1542 {
1543 .name = "wm831x-aldo",
1544 .id = 9,
1545 .num_resources = ARRAY_SIZE(wm831x_ldo9_resources),
1546 .resources = wm831x_ldo9_resources,
1547 },
1548 {
1549 .name = "wm831x-aldo",
1550 .id = 10,
1551 .num_resources = ARRAY_SIZE(wm831x_ldo10_resources),
1552 .resources = wm831x_ldo10_resources,
1553 },
1554 {
1555 .name = "wm831x-alive-ldo",
1556 .id = 11,
1557 .num_resources = ARRAY_SIZE(wm831x_ldo11_resources),
1558 .resources = wm831x_ldo11_resources,
1559 },
1560 {
1561 .name = "wm831x-on",
1562 .num_resources = ARRAY_SIZE(wm831x_on_resources),
1563 .resources = wm831x_on_resources,
1564 },
1565 {
Mark Brownd4e0a892009-10-01 15:41:07 +01001566 .name = "wm831x-status",
1567 .id = 1,
1568 .num_resources = ARRAY_SIZE(wm831x_status1_resources),
1569 .resources = wm831x_status1_resources,
1570 },
1571 {
1572 .name = "wm831x-status",
1573 .id = 2,
1574 .num_resources = ARRAY_SIZE(wm831x_status2_resources),
1575 .resources = wm831x_status2_resources,
1576 },
1577 {
1578 .name = "wm831x-watchdog",
1579 .num_resources = ARRAY_SIZE(wm831x_wdt_resources),
1580 .resources = wm831x_wdt_resources,
1581 },
1582};
1583
Geert Uytterhoevenad59de42013-11-18 14:33:04 +01001584static const struct mfd_cell touch_devs[] = {
Mark Brown266a5e02011-06-02 19:18:49 +01001585 {
1586 .name = "wm831x-touch",
1587 .num_resources = ARRAY_SIZE(wm831x_touch_resources),
1588 .resources = wm831x_touch_resources,
1589 },
1590};
1591
Geert Uytterhoevenad59de42013-11-18 14:33:04 +01001592static const struct mfd_cell rtc_devs[] = {
Mark Brownb9d03d92011-06-02 19:18:50 +01001593 {
1594 .name = "wm831x-rtc",
1595 .num_resources = ARRAY_SIZE(wm831x_rtc_resources),
1596 .resources = wm831x_rtc_resources,
1597 },
1598};
Mark Brown266a5e02011-06-02 19:18:49 +01001599
Geert Uytterhoevenad59de42013-11-18 14:33:04 +01001600static const struct mfd_cell backlight_devs[] = {
Mark Brown63aed852009-07-27 14:45:55 +01001601 {
1602 .name = "wm831x-backlight",
1603 },
1604};
1605
Mark Brown1df59812011-06-10 19:28:10 +01001606struct regmap_config wm831x_regmap_config = {
1607 .reg_bits = 16,
1608 .val_bits = 16,
Mark Brown2e47fff2011-07-21 17:30:08 +01001609
Mark Brown7cccbdc2011-10-09 13:38:06 +01001610 .cache_type = REGCACHE_RBTREE,
1611
Mark Brown2e47fff2011-07-21 17:30:08 +01001612 .max_register = WM831X_DBE_CHECK_DATA,
1613 .readable_reg = wm831x_reg_readable,
1614 .writeable_reg = wm831x_reg_writeable,
1615 .volatile_reg = wm831x_reg_volatile,
Mark Brown1df59812011-06-10 19:28:10 +01001616};
1617EXPORT_SYMBOL_GPL(wm831x_regmap_config);
1618
Charles Keepaxf6dd8442017-03-17 10:05:18 +00001619const struct of_device_id wm831x_of_match[] = {
1620 { .compatible = "wlf,wm8310", .data = (void *)WM8310 },
1621 { .compatible = "wlf,wm8311", .data = (void *)WM8311 },
1622 { .compatible = "wlf,wm8312", .data = (void *)WM8312 },
1623 { .compatible = "wlf,wm8320", .data = (void *)WM8320 },
1624 { .compatible = "wlf,wm8321", .data = (void *)WM8321 },
1625 { .compatible = "wlf,wm8325", .data = (void *)WM8325 },
1626 { .compatible = "wlf,wm8326", .data = (void *)WM8326 },
1627 { },
1628};
1629EXPORT_SYMBOL_GPL(wm831x_of_match);
1630
Mark Brownd2bedfe2009-07-27 14:45:52 +01001631/*
1632 * Instantiate the generic non-control parts of the device.
1633 */
Charles Keepaxf6dd8442017-03-17 10:05:18 +00001634int wm831x_device_init(struct wm831x *wm831x, int irq)
Mark Brownd2bedfe2009-07-27 14:45:52 +01001635{
Charles Keepaxf6dd8442017-03-17 10:05:18 +00001636 struct wm831x_pdata *pdata = &wm831x->pdata;
Mark Browneb503dc2011-06-02 19:18:48 +01001637 int rev, wm831x_num;
Mark Brownd2bedfe2009-07-27 14:45:52 +01001638 enum wm831x_parent parent;
Mark Brown0b14c222011-04-04 11:04:42 +09001639 int ret, i;
Mark Brownd2bedfe2009-07-27 14:45:52 +01001640
1641 mutex_init(&wm831x->io_lock);
1642 mutex_init(&wm831x->key_lock);
1643 dev_set_drvdata(wm831x->dev, wm831x);
Javier Martinez Canillas16dfd102015-09-14 11:07:56 +02001644
Charles Keepaxf6dd8442017-03-17 10:05:18 +00001645 wm831x->soft_shutdown = pdata->soft_shutdown;
Mark Brownd2bedfe2009-07-27 14:45:52 +01001646
1647 ret = wm831x_reg_read(wm831x, WM831X_PARENT_ID);
1648 if (ret < 0) {
1649 dev_err(wm831x->dev, "Failed to read parent ID: %d\n", ret);
Mark Brown130a7032012-01-30 20:08:06 +00001650 goto err;
Mark Brownd2bedfe2009-07-27 14:45:52 +01001651 }
Mark Brownb93cef52010-12-02 16:25:43 +00001652 switch (ret) {
1653 case 0x6204:
1654 case 0x6246:
1655 break;
1656 default:
Mark Brownd2bedfe2009-07-27 14:45:52 +01001657 dev_err(wm831x->dev, "Device is not a WM831x: ID %x\n", ret);
1658 ret = -EINVAL;
Mark Brown130a7032012-01-30 20:08:06 +00001659 goto err;
Mark Brownd2bedfe2009-07-27 14:45:52 +01001660 }
1661
1662 ret = wm831x_reg_read(wm831x, WM831X_REVISION);
1663 if (ret < 0) {
1664 dev_err(wm831x->dev, "Failed to read revision: %d\n", ret);
Mark Brown130a7032012-01-30 20:08:06 +00001665 goto err;
Mark Brownd2bedfe2009-07-27 14:45:52 +01001666 }
1667 rev = (ret & WM831X_PARENT_REV_MASK) >> WM831X_PARENT_REV_SHIFT;
1668
1669 ret = wm831x_reg_read(wm831x, WM831X_RESET_ID);
1670 if (ret < 0) {
1671 dev_err(wm831x->dev, "Failed to read device ID: %d\n", ret);
Mark Brown130a7032012-01-30 20:08:06 +00001672 goto err;
Mark Brownd2bedfe2009-07-27 14:45:52 +01001673 }
1674
Mark Brown894362f2009-10-01 15:41:04 +01001675 /* Some engineering samples do not have the ID set, rely on
1676 * the device being registered correctly.
1677 */
1678 if (ret == 0) {
1679 dev_info(wm831x->dev, "Device is an engineering sample\n");
Charles Keepaxf6dd8442017-03-17 10:05:18 +00001680 ret = wm831x->type;
Mark Brown894362f2009-10-01 15:41:04 +01001681 }
1682
Mark Brownd2bedfe2009-07-27 14:45:52 +01001683 switch (ret) {
Mark Brown894362f2009-10-01 15:41:04 +01001684 case WM8310:
Mark Brownd2bedfe2009-07-27 14:45:52 +01001685 parent = WM8310;
Mark Brown6f2ecaa2009-10-01 15:41:05 +01001686 wm831x->num_gpio = 16;
Mark Brownb03b4d72010-04-08 10:02:39 +02001687 wm831x->charger_irq_wake = 1;
Mark Brownf92e8f82010-02-17 18:45:25 +00001688 if (rev > 0) {
1689 wm831x->has_gpio_ena = 1;
1690 wm831x->has_cs_sts = 1;
1691 }
1692
Mark Brown894362f2009-10-01 15:41:04 +01001693 dev_info(wm831x->dev, "WM8310 revision %c\n", 'A' + rev);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001694 break;
1695
Mark Brown894362f2009-10-01 15:41:04 +01001696 case WM8311:
Mark Brownd2bedfe2009-07-27 14:45:52 +01001697 parent = WM8311;
Mark Brown6f2ecaa2009-10-01 15:41:05 +01001698 wm831x->num_gpio = 16;
Mark Brownb03b4d72010-04-08 10:02:39 +02001699 wm831x->charger_irq_wake = 1;
Mark Brownf92e8f82010-02-17 18:45:25 +00001700 if (rev > 0) {
1701 wm831x->has_gpio_ena = 1;
1702 wm831x->has_cs_sts = 1;
1703 }
1704
Mark Brown894362f2009-10-01 15:41:04 +01001705 dev_info(wm831x->dev, "WM8311 revision %c\n", 'A' + rev);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001706 break;
1707
Mark Brown894362f2009-10-01 15:41:04 +01001708 case WM8312:
Mark Brownd2bedfe2009-07-27 14:45:52 +01001709 parent = WM8312;
Mark Brown6f2ecaa2009-10-01 15:41:05 +01001710 wm831x->num_gpio = 16;
Mark Brownb03b4d72010-04-08 10:02:39 +02001711 wm831x->charger_irq_wake = 1;
Mark Brownf92e8f82010-02-17 18:45:25 +00001712 if (rev > 0) {
1713 wm831x->has_gpio_ena = 1;
1714 wm831x->has_cs_sts = 1;
1715 }
1716
Mark Brown894362f2009-10-01 15:41:04 +01001717 dev_info(wm831x->dev, "WM8312 revision %c\n", 'A' + rev);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001718 break;
1719
Mark Brownd4e0a892009-10-01 15:41:07 +01001720 case WM8320:
1721 parent = WM8320;
1722 wm831x->num_gpio = 12;
1723 dev_info(wm831x->dev, "WM8320 revision %c\n", 'A' + rev);
1724 break;
1725
Mark Brown88913522010-07-21 14:23:37 +01001726 case WM8321:
1727 parent = WM8321;
1728 wm831x->num_gpio = 12;
1729 dev_info(wm831x->dev, "WM8321 revision %c\n", 'A' + rev);
1730 break;
1731
Mark Brown0b315882010-09-28 09:13:39 -07001732 case WM8325:
1733 parent = WM8325;
1734 wm831x->num_gpio = 12;
1735 dev_info(wm831x->dev, "WM8325 revision %c\n", 'A' + rev);
1736 break;
1737
Mark Brown412dc112010-11-24 18:01:41 +00001738 case WM8326:
1739 parent = WM8326;
1740 wm831x->num_gpio = 12;
1741 dev_info(wm831x->dev, "WM8326 revision %c\n", 'A' + rev);
1742 break;
1743
Mark Brownd2bedfe2009-07-27 14:45:52 +01001744 default:
1745 dev_err(wm831x->dev, "Unknown WM831x device %04x\n", ret);
1746 ret = -EINVAL;
Mark Brown130a7032012-01-30 20:08:06 +00001747 goto err;
Mark Brownd2bedfe2009-07-27 14:45:52 +01001748 }
1749
1750 /* This will need revisiting in future but is OK for all
1751 * current parts.
1752 */
Charles Keepaxf6dd8442017-03-17 10:05:18 +00001753 if (parent != wm831x->type)
1754 dev_warn(wm831x->dev, "Device was registered as a WM%x\n",
1755 wm831x->type);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001756
1757 /* Bootstrap the user key */
1758 ret = wm831x_reg_read(wm831x, WM831X_SECURITY_KEY);
1759 if (ret < 0) {
1760 dev_err(wm831x->dev, "Failed to read security key: %d\n", ret);
Mark Brown130a7032012-01-30 20:08:06 +00001761 goto err;
Mark Brownd2bedfe2009-07-27 14:45:52 +01001762 }
1763 if (ret != 0) {
1764 dev_warn(wm831x->dev, "Security key had non-zero value %x\n",
1765 ret);
1766 wm831x_reg_write(wm831x, WM831X_SECURITY_KEY, 0);
1767 }
1768 wm831x->locked = 1;
1769
Charles Keepaxdcb0574b2017-05-15 13:51:24 +01001770 if (pdata->pre_init) {
Mark Brownd2bedfe2009-07-27 14:45:52 +01001771 ret = pdata->pre_init(wm831x);
1772 if (ret != 0) {
1773 dev_err(wm831x->dev, "pre_init() failed: %d\n", ret);
Mark Brown130a7032012-01-30 20:08:06 +00001774 goto err;
Mark Brownd2bedfe2009-07-27 14:45:52 +01001775 }
1776 }
1777
Charles Keepaxdcb0574b2017-05-15 13:51:24 +01001778 for (i = 0; i < ARRAY_SIZE(pdata->gpio_defaults); i++) {
1779 if (!pdata->gpio_defaults[i])
1780 continue;
Mark Brown0b14c222011-04-04 11:04:42 +09001781
Charles Keepaxdcb0574b2017-05-15 13:51:24 +01001782 wm831x_reg_write(wm831x,
1783 WM831X_GPIO1_CONTROL + i,
1784 pdata->gpio_defaults[i] & 0xffff);
Mark Brown0b14c222011-04-04 11:04:42 +09001785 }
1786
Mark Browneb503dc2011-06-02 19:18:48 +01001787 /* Multiply by 10 as we have many subdevices of the same type */
Charles Keepaxdcb0574b2017-05-15 13:51:24 +01001788 if (pdata->wm831x_num)
Mark Browneb503dc2011-06-02 19:18:48 +01001789 wm831x_num = pdata->wm831x_num * 10;
1790 else
1791 wm831x_num = -1;
1792
Mark Brown7d4d0a32009-07-27 14:45:53 +01001793 ret = wm831x_irq_init(wm831x, irq);
1794 if (ret != 0)
Mark Brown130a7032012-01-30 20:08:06 +00001795 goto err;
Mark Brown7d4d0a32009-07-27 14:45:53 +01001796
Mark Browne69b6de2011-06-02 19:18:53 +01001797 wm831x_auxadc_init(wm831x);
Mark Brown473fe732010-02-23 11:08:06 +00001798
Mark Brownd2bedfe2009-07-27 14:45:52 +01001799 /* The core device is up, instantiate the subdevices. */
1800 switch (parent) {
1801 case WM8310:
Mark Browneb503dc2011-06-02 19:18:48 +01001802 ret = mfd_add_devices(wm831x->dev, wm831x_num,
Mark Brownd2bedfe2009-07-27 14:45:52 +01001803 wm8310_devs, ARRAY_SIZE(wm8310_devs),
Mark Brown55692af2012-09-11 15:16:36 +08001804 NULL, 0, NULL);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001805 break;
1806
1807 case WM8311:
Mark Browneb503dc2011-06-02 19:18:48 +01001808 ret = mfd_add_devices(wm831x->dev, wm831x_num,
Mark Brownd2bedfe2009-07-27 14:45:52 +01001809 wm8311_devs, ARRAY_SIZE(wm8311_devs),
Mark Brown55692af2012-09-11 15:16:36 +08001810 NULL, 0, NULL);
Charles Keepaxdcb0574b2017-05-15 13:51:24 +01001811 if (!pdata->disable_touch)
Mark Brown266a5e02011-06-02 19:18:49 +01001812 mfd_add_devices(wm831x->dev, wm831x_num,
1813 touch_devs, ARRAY_SIZE(touch_devs),
Mark Brown55692af2012-09-11 15:16:36 +08001814 NULL, 0, NULL);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001815 break;
1816
1817 case WM8312:
Mark Browneb503dc2011-06-02 19:18:48 +01001818 ret = mfd_add_devices(wm831x->dev, wm831x_num,
Mark Brownd2bedfe2009-07-27 14:45:52 +01001819 wm8312_devs, ARRAY_SIZE(wm8312_devs),
Mark Brown55692af2012-09-11 15:16:36 +08001820 NULL, 0, NULL);
Charles Keepaxdcb0574b2017-05-15 13:51:24 +01001821 if (!pdata->disable_touch)
Mark Brown266a5e02011-06-02 19:18:49 +01001822 mfd_add_devices(wm831x->dev, wm831x_num,
1823 touch_devs, ARRAY_SIZE(touch_devs),
Mark Brown55692af2012-09-11 15:16:36 +08001824 NULL, 0, NULL);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001825 break;
1826
Mark Brownd4e0a892009-10-01 15:41:07 +01001827 case WM8320:
Mark Brown88913522010-07-21 14:23:37 +01001828 case WM8321:
Mark Brown0b315882010-09-28 09:13:39 -07001829 case WM8325:
Mark Brown412dc112010-11-24 18:01:41 +00001830 case WM8326:
Mark Browneb503dc2011-06-02 19:18:48 +01001831 ret = mfd_add_devices(wm831x->dev, wm831x_num,
Mark Brown0b315882010-09-28 09:13:39 -07001832 wm8320_devs, ARRAY_SIZE(wm8320_devs),
Mark Brown55692af2012-09-11 15:16:36 +08001833 NULL, 0, NULL);
Mark Brown0b315882010-09-28 09:13:39 -07001834 break;
1835
Mark Brownd2bedfe2009-07-27 14:45:52 +01001836 default:
1837 /* If this happens the bus probe function is buggy */
1838 BUG();
1839 }
1840
1841 if (ret != 0) {
1842 dev_err(wm831x->dev, "Failed to add children\n");
Mark Brown7d4d0a32009-07-27 14:45:53 +01001843 goto err_irq;
Mark Brownd2bedfe2009-07-27 14:45:52 +01001844 }
1845
Mark Brownb9d03d92011-06-02 19:18:50 +01001846 /* The RTC can only be used if the 32.768kHz crystal is
1847 * enabled; this can't be controlled by software at runtime.
1848 */
1849 ret = wm831x_reg_read(wm831x, WM831X_CLOCK_CONTROL_2);
1850 if (ret < 0) {
1851 dev_err(wm831x->dev, "Failed to read clock status: %d\n", ret);
1852 goto err_irq;
1853 }
1854
1855 if (ret & WM831X_XTAL_ENA) {
1856 ret = mfd_add_devices(wm831x->dev, wm831x_num,
1857 rtc_devs, ARRAY_SIZE(rtc_devs),
Mark Brown55692af2012-09-11 15:16:36 +08001858 NULL, 0, NULL);
Mark Brownb9d03d92011-06-02 19:18:50 +01001859 if (ret != 0) {
1860 dev_err(wm831x->dev, "Failed to add RTC: %d\n", ret);
1861 goto err_irq;
1862 }
1863 } else {
1864 dev_info(wm831x->dev, "32.768kHz clock disabled, no RTC\n");
1865 }
1866
Charles Keepaxdcb0574b2017-05-15 13:51:24 +01001867 if (pdata->backlight) {
Mark Brown63aed852009-07-27 14:45:55 +01001868 /* Treat errors as non-critical */
Mark Browneb503dc2011-06-02 19:18:48 +01001869 ret = mfd_add_devices(wm831x->dev, wm831x_num, backlight_devs,
Mark Brown5fb4d382009-11-11 16:10:22 +00001870 ARRAY_SIZE(backlight_devs), NULL,
Mark Brown55692af2012-09-11 15:16:36 +08001871 0, NULL);
Mark Brown63aed852009-07-27 14:45:55 +01001872 if (ret < 0)
1873 dev_err(wm831x->dev, "Failed to add backlight: %d\n",
1874 ret);
1875 }
1876
Mark Brown6704e512009-07-27 14:45:56 +01001877 wm831x_otp_init(wm831x);
1878
Charles Keepaxdcb0574b2017-05-15 13:51:24 +01001879 if (pdata->post_init) {
Mark Brownd2bedfe2009-07-27 14:45:52 +01001880 ret = pdata->post_init(wm831x);
1881 if (ret != 0) {
1882 dev_err(wm831x->dev, "post_init() failed: %d\n", ret);
Mark Brown7d4d0a32009-07-27 14:45:53 +01001883 goto err_irq;
Mark Brownd2bedfe2009-07-27 14:45:52 +01001884 }
1885 }
1886
1887 return 0;
1888
Mark Brown7d4d0a32009-07-27 14:45:53 +01001889err_irq:
1890 wm831x_irq_exit(wm831x);
Mark Brown130a7032012-01-30 20:08:06 +00001891err:
Mark Brownd2bedfe2009-07-27 14:45:52 +01001892 mfd_remove_devices(wm831x->dev);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001893 return ret;
1894}
1895
Mark Browne5b48682010-10-19 23:57:56 +02001896int wm831x_device_suspend(struct wm831x *wm831x)
Mark Brownb03b4d72010-04-08 10:02:39 +02001897{
1898 int reg, mask;
1899
1900 /* If the charger IRQs are a wake source then make sure we ack
1901 * them even if they're not actively being used (eg, no power
1902 * driver or no IRQ line wired up) then acknowledge the
1903 * interrupts otherwise suspend won't last very long.
1904 */
1905 if (wm831x->charger_irq_wake) {
1906 reg = wm831x_reg_read(wm831x, WM831X_INTERRUPT_STATUS_2_MASK);
1907
1908 mask = WM831X_CHG_BATT_HOT_EINT |
1909 WM831X_CHG_BATT_COLD_EINT |
1910 WM831X_CHG_BATT_FAIL_EINT |
1911 WM831X_CHG_OV_EINT | WM831X_CHG_END_EINT |
1912 WM831X_CHG_TO_EINT | WM831X_CHG_MODE_EINT |
1913 WM831X_CHG_START_EINT;
1914
1915 /* If any of the interrupts are masked read the statuses */
1916 if (reg & mask)
1917 reg = wm831x_reg_read(wm831x,
1918 WM831X_INTERRUPT_STATUS_2);
1919
1920 if (reg & mask) {
1921 dev_info(wm831x->dev,
1922 "Acknowledging masked charger IRQs: %x\n",
1923 reg & mask);
1924 wm831x_reg_write(wm831x, WM831X_INTERRUPT_STATUS_2,
1925 reg & mask);
1926 }
1927 }
1928
1929 return 0;
1930}
1931
Mark Brown523d9cf2011-09-15 18:54:53 +02001932void wm831x_device_shutdown(struct wm831x *wm831x)
1933{
1934 if (wm831x->soft_shutdown) {
1935 dev_info(wm831x->dev, "Initiating shutdown...\n");
1936 wm831x_set_bits(wm831x, WM831X_POWER_STATE, WM831X_CHIP_ON, 0);
1937 }
1938}
1939EXPORT_SYMBOL_GPL(wm831x_device_shutdown);