blob: d2f444d2ae78f3e9f7cba8da19bce866b0f60d5a [file] [log] [blame]
Thomas Gleixner2874c5f2019-05-27 08:55:01 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Mark Brownd2bedfe2009-07-27 14:45:52 +01002/*
3 * wm831x-core.c -- Device access for Wolfson WM831x PMICs
4 *
5 * Copyright 2009 Wolfson Microelectronics PLC.
6 *
7 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
Mark Brownd2bedfe2009-07-27 14:45:52 +01008 */
9
10#include <linux/kernel.h>
Paul Gortmakerefb5a792019-01-13 13:36:46 -050011#include <linux/init.h>
12#include <linux/export.h>
Mark Brown7e9f9fd2009-07-27 14:45:54 +010013#include <linux/bcd.h>
14#include <linux/delay.h>
Mark Brownd2bedfe2009-07-27 14:45:52 +010015#include <linux/mfd/core.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090016#include <linux/slab.h>
Mark Brown1df59812011-06-10 19:28:10 +010017#include <linux/err.h>
Charles Keepaxf6dd8442017-03-17 10:05:18 +000018#include <linux/of.h>
19#include <linux/of_device.h>
Mark Brownd2bedfe2009-07-27 14:45:52 +010020
21#include <linux/mfd/wm831x/core.h>
22#include <linux/mfd/wm831x/pdata.h>
Mark Brown7d4d0a32009-07-27 14:45:53 +010023#include <linux/mfd/wm831x/irq.h>
Mark Brown7e9f9fd2009-07-27 14:45:54 +010024#include <linux/mfd/wm831x/auxadc.h>
Mark Brown6704e512009-07-27 14:45:56 +010025#include <linux/mfd/wm831x/otp.h>
Mark Brown523d9cf2011-09-15 18:54:53 +020026#include <linux/mfd/wm831x/pmu.h>
Mark Brown698659d2009-07-27 14:45:57 +010027#include <linux/mfd/wm831x/regulator.h>
28
29/* Current settings - values are 2*2^(reg_val/4) microamps. These are
30 * exported since they are used by multiple drivers.
31 */
Axel Lind48acfd2019-03-13 00:33:56 +080032const unsigned int wm831x_isinkv_values[WM831X_ISINK_MAX_ISEL + 1] = {
Mark Brown698659d2009-07-27 14:45:57 +010033 2,
34 2,
35 3,
36 3,
37 4,
38 5,
39 6,
40 7,
41 8,
42 10,
43 11,
44 13,
45 16,
46 19,
47 23,
48 27,
49 32,
50 38,
51 45,
52 54,
53 64,
54 76,
55 91,
56 108,
57 128,
58 152,
59 181,
60 215,
61 256,
62 304,
63 362,
64 431,
65 512,
66 609,
67 724,
68 861,
69 1024,
70 1218,
71 1448,
72 1722,
73 2048,
74 2435,
75 2896,
76 3444,
77 4096,
78 4871,
79 5793,
80 6889,
81 8192,
82 9742,
83 11585,
84 13777,
85 16384,
86 19484,
87 23170,
88 27554,
89};
90EXPORT_SYMBOL_GPL(wm831x_isinkv_values);
Mark Brownd2bedfe2009-07-27 14:45:52 +010091
Mark Brownd2bedfe2009-07-27 14:45:52 +010092static int wm831x_reg_locked(struct wm831x *wm831x, unsigned short reg)
93{
94 if (!wm831x->locked)
95 return 0;
96
97 switch (reg) {
98 case WM831X_WATCHDOG:
99 case WM831X_DC4_CONTROL:
100 case WM831X_ON_PIN_CONTROL:
101 case WM831X_BACKUP_CHARGER_CONTROL:
102 case WM831X_CHARGER_CONTROL_1:
103 case WM831X_CHARGER_CONTROL_2:
104 return 1;
105
106 default:
107 return 0;
108 }
109}
110
111/**
Lee Jones926337b2021-03-31 09:09:46 +0100112 * wm831x_reg_lock: Unlock user keyed registers
Mark Brownd2bedfe2009-07-27 14:45:52 +0100113 *
114 * The WM831x has a user key preventing writes to particularly
115 * critical registers. This function locks those registers,
116 * allowing writes to them.
Lee Jones38ea9f42020-06-23 15:33:33 +0100117 *
118 * @wm831x: pointer to local driver data structure
Mark Brownd2bedfe2009-07-27 14:45:52 +0100119 */
120void wm831x_reg_lock(struct wm831x *wm831x)
121{
122 int ret;
123
124 ret = wm831x_reg_write(wm831x, WM831X_SECURITY_KEY, 0);
125 if (ret == 0) {
126 dev_vdbg(wm831x->dev, "Registers locked\n");
127
128 mutex_lock(&wm831x->io_lock);
129 WARN_ON(wm831x->locked);
130 wm831x->locked = 1;
131 mutex_unlock(&wm831x->io_lock);
132 } else {
133 dev_err(wm831x->dev, "Failed to lock registers: %d\n", ret);
134 }
135
136}
137EXPORT_SYMBOL_GPL(wm831x_reg_lock);
138
139/**
140 * wm831x_reg_unlock: Unlock user keyed registers
141 *
142 * The WM831x has a user key preventing writes to particularly
143 * critical registers. This function locks those registers,
144 * preventing spurious writes.
Lee Jones38ea9f42020-06-23 15:33:33 +0100145 *
146 * @wm831x: pointer to local driver data structure
Mark Brownd2bedfe2009-07-27 14:45:52 +0100147 */
148int wm831x_reg_unlock(struct wm831x *wm831x)
149{
150 int ret;
151
152 /* 0x9716 is the value required to unlock the registers */
153 ret = wm831x_reg_write(wm831x, WM831X_SECURITY_KEY, 0x9716);
154 if (ret == 0) {
155 dev_vdbg(wm831x->dev, "Registers unlocked\n");
156
157 mutex_lock(&wm831x->io_lock);
158 WARN_ON(!wm831x->locked);
159 wm831x->locked = 0;
160 mutex_unlock(&wm831x->io_lock);
161 }
162
163 return ret;
164}
165EXPORT_SYMBOL_GPL(wm831x_reg_unlock);
166
Mark Brown2e47fff2011-07-21 17:30:08 +0100167static bool wm831x_reg_readable(struct device *dev, unsigned int reg)
168{
169 switch (reg) {
170 case WM831X_RESET_ID:
171 case WM831X_REVISION:
172 case WM831X_PARENT_ID:
173 case WM831X_SYSVDD_CONTROL:
174 case WM831X_THERMAL_MONITORING:
175 case WM831X_POWER_STATE:
176 case WM831X_WATCHDOG:
177 case WM831X_ON_PIN_CONTROL:
178 case WM831X_RESET_CONTROL:
179 case WM831X_CONTROL_INTERFACE:
180 case WM831X_SECURITY_KEY:
181 case WM831X_SOFTWARE_SCRATCH:
182 case WM831X_OTP_CONTROL:
183 case WM831X_GPIO_LEVEL:
184 case WM831X_SYSTEM_STATUS:
185 case WM831X_ON_SOURCE:
186 case WM831X_OFF_SOURCE:
187 case WM831X_SYSTEM_INTERRUPTS:
188 case WM831X_INTERRUPT_STATUS_1:
189 case WM831X_INTERRUPT_STATUS_2:
190 case WM831X_INTERRUPT_STATUS_3:
191 case WM831X_INTERRUPT_STATUS_4:
192 case WM831X_INTERRUPT_STATUS_5:
193 case WM831X_IRQ_CONFIG:
194 case WM831X_SYSTEM_INTERRUPTS_MASK:
195 case WM831X_INTERRUPT_STATUS_1_MASK:
196 case WM831X_INTERRUPT_STATUS_2_MASK:
197 case WM831X_INTERRUPT_STATUS_3_MASK:
198 case WM831X_INTERRUPT_STATUS_4_MASK:
199 case WM831X_INTERRUPT_STATUS_5_MASK:
200 case WM831X_RTC_WRITE_COUNTER:
201 case WM831X_RTC_TIME_1:
202 case WM831X_RTC_TIME_2:
203 case WM831X_RTC_ALARM_1:
204 case WM831X_RTC_ALARM_2:
205 case WM831X_RTC_CONTROL:
206 case WM831X_RTC_TRIM:
207 case WM831X_TOUCH_CONTROL_1:
208 case WM831X_TOUCH_CONTROL_2:
209 case WM831X_TOUCH_DATA_X:
210 case WM831X_TOUCH_DATA_Y:
211 case WM831X_TOUCH_DATA_Z:
212 case WM831X_AUXADC_DATA:
213 case WM831X_AUXADC_CONTROL:
214 case WM831X_AUXADC_SOURCE:
215 case WM831X_COMPARATOR_CONTROL:
216 case WM831X_COMPARATOR_1:
217 case WM831X_COMPARATOR_2:
218 case WM831X_COMPARATOR_3:
219 case WM831X_COMPARATOR_4:
220 case WM831X_GPIO1_CONTROL:
221 case WM831X_GPIO2_CONTROL:
222 case WM831X_GPIO3_CONTROL:
223 case WM831X_GPIO4_CONTROL:
224 case WM831X_GPIO5_CONTROL:
225 case WM831X_GPIO6_CONTROL:
226 case WM831X_GPIO7_CONTROL:
227 case WM831X_GPIO8_CONTROL:
228 case WM831X_GPIO9_CONTROL:
229 case WM831X_GPIO10_CONTROL:
230 case WM831X_GPIO11_CONTROL:
231 case WM831X_GPIO12_CONTROL:
232 case WM831X_GPIO13_CONTROL:
233 case WM831X_GPIO14_CONTROL:
234 case WM831X_GPIO15_CONTROL:
235 case WM831X_GPIO16_CONTROL:
236 case WM831X_CHARGER_CONTROL_1:
237 case WM831X_CHARGER_CONTROL_2:
238 case WM831X_CHARGER_STATUS:
239 case WM831X_BACKUP_CHARGER_CONTROL:
240 case WM831X_STATUS_LED_1:
241 case WM831X_STATUS_LED_2:
242 case WM831X_CURRENT_SINK_1:
243 case WM831X_CURRENT_SINK_2:
244 case WM831X_DCDC_ENABLE:
245 case WM831X_LDO_ENABLE:
246 case WM831X_DCDC_STATUS:
247 case WM831X_LDO_STATUS:
248 case WM831X_DCDC_UV_STATUS:
249 case WM831X_LDO_UV_STATUS:
250 case WM831X_DC1_CONTROL_1:
251 case WM831X_DC1_CONTROL_2:
252 case WM831X_DC1_ON_CONFIG:
253 case WM831X_DC1_SLEEP_CONTROL:
254 case WM831X_DC1_DVS_CONTROL:
255 case WM831X_DC2_CONTROL_1:
256 case WM831X_DC2_CONTROL_2:
257 case WM831X_DC2_ON_CONFIG:
258 case WM831X_DC2_SLEEP_CONTROL:
259 case WM831X_DC2_DVS_CONTROL:
260 case WM831X_DC3_CONTROL_1:
261 case WM831X_DC3_CONTROL_2:
262 case WM831X_DC3_ON_CONFIG:
263 case WM831X_DC3_SLEEP_CONTROL:
264 case WM831X_DC4_CONTROL:
265 case WM831X_DC4_SLEEP_CONTROL:
266 case WM831X_EPE1_CONTROL:
267 case WM831X_EPE2_CONTROL:
268 case WM831X_LDO1_CONTROL:
269 case WM831X_LDO1_ON_CONTROL:
270 case WM831X_LDO1_SLEEP_CONTROL:
271 case WM831X_LDO2_CONTROL:
272 case WM831X_LDO2_ON_CONTROL:
273 case WM831X_LDO2_SLEEP_CONTROL:
274 case WM831X_LDO3_CONTROL:
275 case WM831X_LDO3_ON_CONTROL:
276 case WM831X_LDO3_SLEEP_CONTROL:
277 case WM831X_LDO4_CONTROL:
278 case WM831X_LDO4_ON_CONTROL:
279 case WM831X_LDO4_SLEEP_CONTROL:
280 case WM831X_LDO5_CONTROL:
281 case WM831X_LDO5_ON_CONTROL:
282 case WM831X_LDO5_SLEEP_CONTROL:
283 case WM831X_LDO6_CONTROL:
284 case WM831X_LDO6_ON_CONTROL:
285 case WM831X_LDO6_SLEEP_CONTROL:
286 case WM831X_LDO7_CONTROL:
287 case WM831X_LDO7_ON_CONTROL:
288 case WM831X_LDO7_SLEEP_CONTROL:
289 case WM831X_LDO8_CONTROL:
290 case WM831X_LDO8_ON_CONTROL:
291 case WM831X_LDO8_SLEEP_CONTROL:
292 case WM831X_LDO9_CONTROL:
293 case WM831X_LDO9_ON_CONTROL:
294 case WM831X_LDO9_SLEEP_CONTROL:
295 case WM831X_LDO10_CONTROL:
296 case WM831X_LDO10_ON_CONTROL:
297 case WM831X_LDO10_SLEEP_CONTROL:
298 case WM831X_LDO11_ON_CONTROL:
299 case WM831X_LDO11_SLEEP_CONTROL:
300 case WM831X_POWER_GOOD_SOURCE_1:
301 case WM831X_POWER_GOOD_SOURCE_2:
302 case WM831X_CLOCK_CONTROL_1:
303 case WM831X_CLOCK_CONTROL_2:
304 case WM831X_FLL_CONTROL_1:
305 case WM831X_FLL_CONTROL_2:
306 case WM831X_FLL_CONTROL_3:
307 case WM831X_FLL_CONTROL_4:
308 case WM831X_FLL_CONTROL_5:
309 case WM831X_UNIQUE_ID_1:
310 case WM831X_UNIQUE_ID_2:
311 case WM831X_UNIQUE_ID_3:
312 case WM831X_UNIQUE_ID_4:
313 case WM831X_UNIQUE_ID_5:
314 case WM831X_UNIQUE_ID_6:
315 case WM831X_UNIQUE_ID_7:
316 case WM831X_UNIQUE_ID_8:
317 case WM831X_FACTORY_OTP_ID:
318 case WM831X_FACTORY_OTP_1:
319 case WM831X_FACTORY_OTP_2:
320 case WM831X_FACTORY_OTP_3:
321 case WM831X_FACTORY_OTP_4:
322 case WM831X_FACTORY_OTP_5:
323 case WM831X_CUSTOMER_OTP_ID:
324 case WM831X_DC1_OTP_CONTROL:
325 case WM831X_DC2_OTP_CONTROL:
326 case WM831X_DC3_OTP_CONTROL:
327 case WM831X_LDO1_2_OTP_CONTROL:
328 case WM831X_LDO3_4_OTP_CONTROL:
329 case WM831X_LDO5_6_OTP_CONTROL:
330 case WM831X_LDO7_8_OTP_CONTROL:
331 case WM831X_LDO9_10_OTP_CONTROL:
332 case WM831X_LDO11_EPE_CONTROL:
333 case WM831X_GPIO1_OTP_CONTROL:
334 case WM831X_GPIO2_OTP_CONTROL:
335 case WM831X_GPIO3_OTP_CONTROL:
336 case WM831X_GPIO4_OTP_CONTROL:
337 case WM831X_GPIO5_OTP_CONTROL:
338 case WM831X_GPIO6_OTP_CONTROL:
339 case WM831X_DBE_CHECK_DATA:
340 return true;
341 default:
342 return false;
343 }
344}
345
346static bool wm831x_reg_writeable(struct device *dev, unsigned int reg)
347{
348 struct wm831x *wm831x = dev_get_drvdata(dev);
349
350 if (wm831x_reg_locked(wm831x, reg))
351 return false;
352
353 switch (reg) {
354 case WM831X_SYSVDD_CONTROL:
355 case WM831X_THERMAL_MONITORING:
356 case WM831X_POWER_STATE:
357 case WM831X_WATCHDOG:
358 case WM831X_ON_PIN_CONTROL:
359 case WM831X_RESET_CONTROL:
360 case WM831X_CONTROL_INTERFACE:
361 case WM831X_SECURITY_KEY:
362 case WM831X_SOFTWARE_SCRATCH:
363 case WM831X_OTP_CONTROL:
364 case WM831X_GPIO_LEVEL:
365 case WM831X_INTERRUPT_STATUS_1:
366 case WM831X_INTERRUPT_STATUS_2:
367 case WM831X_INTERRUPT_STATUS_3:
368 case WM831X_INTERRUPT_STATUS_4:
369 case WM831X_INTERRUPT_STATUS_5:
370 case WM831X_IRQ_CONFIG:
371 case WM831X_SYSTEM_INTERRUPTS_MASK:
372 case WM831X_INTERRUPT_STATUS_1_MASK:
373 case WM831X_INTERRUPT_STATUS_2_MASK:
374 case WM831X_INTERRUPT_STATUS_3_MASK:
375 case WM831X_INTERRUPT_STATUS_4_MASK:
376 case WM831X_INTERRUPT_STATUS_5_MASK:
377 case WM831X_RTC_TIME_1:
378 case WM831X_RTC_TIME_2:
379 case WM831X_RTC_ALARM_1:
380 case WM831X_RTC_ALARM_2:
381 case WM831X_RTC_CONTROL:
382 case WM831X_RTC_TRIM:
383 case WM831X_TOUCH_CONTROL_1:
384 case WM831X_TOUCH_CONTROL_2:
385 case WM831X_AUXADC_CONTROL:
386 case WM831X_AUXADC_SOURCE:
387 case WM831X_COMPARATOR_CONTROL:
388 case WM831X_COMPARATOR_1:
389 case WM831X_COMPARATOR_2:
390 case WM831X_COMPARATOR_3:
391 case WM831X_COMPARATOR_4:
392 case WM831X_GPIO1_CONTROL:
393 case WM831X_GPIO2_CONTROL:
394 case WM831X_GPIO3_CONTROL:
395 case WM831X_GPIO4_CONTROL:
396 case WM831X_GPIO5_CONTROL:
397 case WM831X_GPIO6_CONTROL:
398 case WM831X_GPIO7_CONTROL:
399 case WM831X_GPIO8_CONTROL:
400 case WM831X_GPIO9_CONTROL:
401 case WM831X_GPIO10_CONTROL:
402 case WM831X_GPIO11_CONTROL:
403 case WM831X_GPIO12_CONTROL:
404 case WM831X_GPIO13_CONTROL:
405 case WM831X_GPIO14_CONTROL:
406 case WM831X_GPIO15_CONTROL:
407 case WM831X_GPIO16_CONTROL:
408 case WM831X_CHARGER_CONTROL_1:
409 case WM831X_CHARGER_CONTROL_2:
410 case WM831X_CHARGER_STATUS:
411 case WM831X_BACKUP_CHARGER_CONTROL:
412 case WM831X_STATUS_LED_1:
413 case WM831X_STATUS_LED_2:
414 case WM831X_CURRENT_SINK_1:
415 case WM831X_CURRENT_SINK_2:
416 case WM831X_DCDC_ENABLE:
417 case WM831X_LDO_ENABLE:
418 case WM831X_DC1_CONTROL_1:
419 case WM831X_DC1_CONTROL_2:
420 case WM831X_DC1_ON_CONFIG:
421 case WM831X_DC1_SLEEP_CONTROL:
422 case WM831X_DC1_DVS_CONTROL:
423 case WM831X_DC2_CONTROL_1:
424 case WM831X_DC2_CONTROL_2:
425 case WM831X_DC2_ON_CONFIG:
426 case WM831X_DC2_SLEEP_CONTROL:
427 case WM831X_DC2_DVS_CONTROL:
428 case WM831X_DC3_CONTROL_1:
429 case WM831X_DC3_CONTROL_2:
430 case WM831X_DC3_ON_CONFIG:
431 case WM831X_DC3_SLEEP_CONTROL:
432 case WM831X_DC4_CONTROL:
433 case WM831X_DC4_SLEEP_CONTROL:
434 case WM831X_EPE1_CONTROL:
435 case WM831X_EPE2_CONTROL:
436 case WM831X_LDO1_CONTROL:
437 case WM831X_LDO1_ON_CONTROL:
438 case WM831X_LDO1_SLEEP_CONTROL:
439 case WM831X_LDO2_CONTROL:
440 case WM831X_LDO2_ON_CONTROL:
441 case WM831X_LDO2_SLEEP_CONTROL:
442 case WM831X_LDO3_CONTROL:
443 case WM831X_LDO3_ON_CONTROL:
444 case WM831X_LDO3_SLEEP_CONTROL:
445 case WM831X_LDO4_CONTROL:
446 case WM831X_LDO4_ON_CONTROL:
447 case WM831X_LDO4_SLEEP_CONTROL:
448 case WM831X_LDO5_CONTROL:
449 case WM831X_LDO5_ON_CONTROL:
450 case WM831X_LDO5_SLEEP_CONTROL:
451 case WM831X_LDO6_CONTROL:
452 case WM831X_LDO6_ON_CONTROL:
453 case WM831X_LDO6_SLEEP_CONTROL:
454 case WM831X_LDO7_CONTROL:
455 case WM831X_LDO7_ON_CONTROL:
456 case WM831X_LDO7_SLEEP_CONTROL:
457 case WM831X_LDO8_CONTROL:
458 case WM831X_LDO8_ON_CONTROL:
459 case WM831X_LDO8_SLEEP_CONTROL:
460 case WM831X_LDO9_CONTROL:
461 case WM831X_LDO9_ON_CONTROL:
462 case WM831X_LDO9_SLEEP_CONTROL:
463 case WM831X_LDO10_CONTROL:
464 case WM831X_LDO10_ON_CONTROL:
465 case WM831X_LDO10_SLEEP_CONTROL:
466 case WM831X_LDO11_ON_CONTROL:
467 case WM831X_LDO11_SLEEP_CONTROL:
468 case WM831X_POWER_GOOD_SOURCE_1:
469 case WM831X_POWER_GOOD_SOURCE_2:
470 case WM831X_CLOCK_CONTROL_1:
471 case WM831X_CLOCK_CONTROL_2:
472 case WM831X_FLL_CONTROL_1:
473 case WM831X_FLL_CONTROL_2:
474 case WM831X_FLL_CONTROL_3:
475 case WM831X_FLL_CONTROL_4:
476 case WM831X_FLL_CONTROL_5:
477 return true;
478 default:
479 return false;
480 }
481}
482
483static bool wm831x_reg_volatile(struct device *dev, unsigned int reg)
484{
485 switch (reg) {
486 case WM831X_SYSTEM_STATUS:
487 case WM831X_ON_SOURCE:
488 case WM831X_OFF_SOURCE:
489 case WM831X_GPIO_LEVEL:
490 case WM831X_SYSTEM_INTERRUPTS:
491 case WM831X_INTERRUPT_STATUS_1:
492 case WM831X_INTERRUPT_STATUS_2:
493 case WM831X_INTERRUPT_STATUS_3:
494 case WM831X_INTERRUPT_STATUS_4:
495 case WM831X_INTERRUPT_STATUS_5:
496 case WM831X_RTC_TIME_1:
497 case WM831X_RTC_TIME_2:
498 case WM831X_TOUCH_DATA_X:
499 case WM831X_TOUCH_DATA_Y:
500 case WM831X_TOUCH_DATA_Z:
501 case WM831X_AUXADC_DATA:
502 case WM831X_CHARGER_STATUS:
503 case WM831X_DCDC_STATUS:
504 case WM831X_LDO_STATUS:
505 case WM831X_DCDC_UV_STATUS:
506 case WM831X_LDO_UV_STATUS:
507 return true;
508 default:
509 return false;
510 }
511}
512
Mark Brownd2bedfe2009-07-27 14:45:52 +0100513/**
514 * wm831x_reg_read: Read a single WM831x register.
515 *
516 * @wm831x: Device to read from.
517 * @reg: Register to read.
518 */
519int wm831x_reg_read(struct wm831x *wm831x, unsigned short reg)
520{
Mark Brown1df59812011-06-10 19:28:10 +0100521 unsigned int val;
Mark Brownd2bedfe2009-07-27 14:45:52 +0100522 int ret;
523
Mark Brown1df59812011-06-10 19:28:10 +0100524 ret = regmap_read(wm831x->regmap, reg, &val);
Mark Brownd2bedfe2009-07-27 14:45:52 +0100525
526 if (ret < 0)
527 return ret;
528 else
529 return val;
530}
531EXPORT_SYMBOL_GPL(wm831x_reg_read);
532
533/**
534 * wm831x_bulk_read: Read multiple WM831x registers
535 *
536 * @wm831x: Device to read from
537 * @reg: First register
538 * @count: Number of registers
539 * @buf: Buffer to fill.
540 */
541int wm831x_bulk_read(struct wm831x *wm831x, unsigned short reg,
542 int count, u16 *buf)
543{
Mark Brown1df59812011-06-10 19:28:10 +0100544 return regmap_bulk_read(wm831x->regmap, reg, buf, count);
Mark Brownd2bedfe2009-07-27 14:45:52 +0100545}
546EXPORT_SYMBOL_GPL(wm831x_bulk_read);
547
548static int wm831x_write(struct wm831x *wm831x, unsigned short reg,
549 int bytes, void *src)
550{
551 u16 *buf = src;
Mark Brown1df59812011-06-10 19:28:10 +0100552 int i, ret;
Mark Brownd2bedfe2009-07-27 14:45:52 +0100553
554 BUG_ON(bytes % 2);
555 BUG_ON(bytes <= 0);
556
557 for (i = 0; i < bytes / 2; i++) {
558 if (wm831x_reg_locked(wm831x, reg))
559 return -EPERM;
560
561 dev_vdbg(wm831x->dev, "Write %04x to R%d(0x%x)\n",
562 buf[i], reg + i, reg + i);
Mark Brown1df59812011-06-10 19:28:10 +0100563 ret = regmap_write(wm831x->regmap, reg + i, buf[i]);
Mark Brown5391b5c2011-12-05 12:01:07 +0000564 if (ret != 0)
565 return ret;
Mark Brownd2bedfe2009-07-27 14:45:52 +0100566 }
567
Mark Brown1df59812011-06-10 19:28:10 +0100568 return 0;
Mark Brownd2bedfe2009-07-27 14:45:52 +0100569}
570
571/**
572 * wm831x_reg_write: Write a single WM831x register.
573 *
574 * @wm831x: Device to write to.
575 * @reg: Register to write to.
576 * @val: Value to write.
577 */
578int wm831x_reg_write(struct wm831x *wm831x, unsigned short reg,
579 unsigned short val)
580{
581 int ret;
582
583 mutex_lock(&wm831x->io_lock);
584
585 ret = wm831x_write(wm831x, reg, 2, &val);
586
587 mutex_unlock(&wm831x->io_lock);
588
589 return ret;
590}
591EXPORT_SYMBOL_GPL(wm831x_reg_write);
592
593/**
594 * wm831x_set_bits: Set the value of a bitfield in a WM831x register
595 *
596 * @wm831x: Device to write to.
597 * @reg: Register to write to.
598 * @mask: Mask of bits to set.
599 * @val: Value to set (unshifted)
600 */
601int wm831x_set_bits(struct wm831x *wm831x, unsigned short reg,
602 unsigned short mask, unsigned short val)
603{
604 int ret;
Mark Brownd2bedfe2009-07-27 14:45:52 +0100605
606 mutex_lock(&wm831x->io_lock);
607
Mark Brown1df59812011-06-10 19:28:10 +0100608 if (!wm831x_reg_locked(wm831x, reg))
609 ret = regmap_update_bits(wm831x->regmap, reg, mask, val);
610 else
611 ret = -EPERM;
Mark Brownd2bedfe2009-07-27 14:45:52 +0100612
Mark Brownd2bedfe2009-07-27 14:45:52 +0100613 mutex_unlock(&wm831x->io_lock);
614
615 return ret;
616}
617EXPORT_SYMBOL_GPL(wm831x_set_bits);
618
Rikard Falkebornf9772842020-09-22 21:26:55 +0200619static const struct resource wm831x_dcdc1_resources[] = {
Mark Brownd2bedfe2009-07-27 14:45:52 +0100620 {
621 .start = WM831X_DC1_CONTROL_1,
622 .end = WM831X_DC1_DVS_CONTROL,
Mark Brown56560982012-08-07 19:42:47 +0100623 .flags = IORESOURCE_REG,
Mark Brownd2bedfe2009-07-27 14:45:52 +0100624 },
Zhen Lei3da286a2021-06-01 15:00:09 +0800625 DEFINE_RES_IRQ_NAMED(WM831X_IRQ_UV_DC1, "UV"),
626 DEFINE_RES_IRQ_NAMED(WM831X_IRQ_HC_DC1, "HC"),
Mark Brownd2bedfe2009-07-27 14:45:52 +0100627};
628
629
Rikard Falkebornf9772842020-09-22 21:26:55 +0200630static const struct resource wm831x_dcdc2_resources[] = {
Mark Brownd2bedfe2009-07-27 14:45:52 +0100631 {
632 .start = WM831X_DC2_CONTROL_1,
633 .end = WM831X_DC2_DVS_CONTROL,
Mark Brown56560982012-08-07 19:42:47 +0100634 .flags = IORESOURCE_REG,
Mark Brownd2bedfe2009-07-27 14:45:52 +0100635 },
Zhen Lei3da286a2021-06-01 15:00:09 +0800636 DEFINE_RES_IRQ_NAMED(WM831X_IRQ_UV_DC2, "UV"),
637 DEFINE_RES_IRQ_NAMED(WM831X_IRQ_HC_DC2, "HC"),
Mark Brownd2bedfe2009-07-27 14:45:52 +0100638};
639
Rikard Falkebornf9772842020-09-22 21:26:55 +0200640static const struct resource wm831x_dcdc3_resources[] = {
Mark Brownd2bedfe2009-07-27 14:45:52 +0100641 {
642 .start = WM831X_DC3_CONTROL_1,
643 .end = WM831X_DC3_SLEEP_CONTROL,
Mark Brown56560982012-08-07 19:42:47 +0100644 .flags = IORESOURCE_REG,
Mark Brownd2bedfe2009-07-27 14:45:52 +0100645 },
Zhen Lei3da286a2021-06-01 15:00:09 +0800646 DEFINE_RES_IRQ_NAMED(WM831X_IRQ_UV_DC3, "UV"),
Mark Brownd2bedfe2009-07-27 14:45:52 +0100647};
648
Rikard Falkebornf9772842020-09-22 21:26:55 +0200649static const struct resource wm831x_dcdc4_resources[] = {
Mark Brownd2bedfe2009-07-27 14:45:52 +0100650 {
651 .start = WM831X_DC4_CONTROL,
652 .end = WM831X_DC4_SLEEP_CONTROL,
Mark Brown56560982012-08-07 19:42:47 +0100653 .flags = IORESOURCE_REG,
Mark Brownd2bedfe2009-07-27 14:45:52 +0100654 },
Zhen Lei3da286a2021-06-01 15:00:09 +0800655 DEFINE_RES_IRQ_NAMED(WM831X_IRQ_UV_DC4, "UV"),
Mark Brownd2bedfe2009-07-27 14:45:52 +0100656};
657
Rikard Falkebornf9772842020-09-22 21:26:55 +0200658static const struct resource wm8320_dcdc4_buck_resources[] = {
Mark Brownd4e0a892009-10-01 15:41:07 +0100659 {
660 .start = WM831X_DC4_CONTROL,
661 .end = WM832X_DC4_SLEEP_CONTROL,
Mark Brown56560982012-08-07 19:42:47 +0100662 .flags = IORESOURCE_REG,
Mark Brownd4e0a892009-10-01 15:41:07 +0100663 },
Zhen Lei3da286a2021-06-01 15:00:09 +0800664 DEFINE_RES_IRQ_NAMED(WM831X_IRQ_UV_DC4, "UV"),
Mark Brownd4e0a892009-10-01 15:41:07 +0100665};
666
Rikard Falkebornf9772842020-09-22 21:26:55 +0200667static const struct resource wm831x_gpio_resources[] = {
Mark Brownd2bedfe2009-07-27 14:45:52 +0100668 {
669 .start = WM831X_IRQ_GPIO_1,
670 .end = WM831X_IRQ_GPIO_16,
671 .flags = IORESOURCE_IRQ,
672 },
673};
674
Rikard Falkebornf9772842020-09-22 21:26:55 +0200675static const struct resource wm831x_isink1_resources[] = {
Mark Brownd2bedfe2009-07-27 14:45:52 +0100676 {
677 .start = WM831X_CURRENT_SINK_1,
678 .end = WM831X_CURRENT_SINK_1,
Mark Brown56560982012-08-07 19:42:47 +0100679 .flags = IORESOURCE_REG,
Mark Brownd2bedfe2009-07-27 14:45:52 +0100680 },
Zhen Lei3da286a2021-06-01 15:00:09 +0800681 DEFINE_RES_IRQ(WM831X_IRQ_CS1),
Mark Brownd2bedfe2009-07-27 14:45:52 +0100682};
683
Rikard Falkebornf9772842020-09-22 21:26:55 +0200684static const struct resource wm831x_isink2_resources[] = {
Mark Brownd2bedfe2009-07-27 14:45:52 +0100685 {
686 .start = WM831X_CURRENT_SINK_2,
687 .end = WM831X_CURRENT_SINK_2,
Mark Brown56560982012-08-07 19:42:47 +0100688 .flags = IORESOURCE_REG,
Mark Brownd2bedfe2009-07-27 14:45:52 +0100689 },
Zhen Lei3da286a2021-06-01 15:00:09 +0800690 DEFINE_RES_IRQ(WM831X_IRQ_CS2),
Mark Brownd2bedfe2009-07-27 14:45:52 +0100691};
692
Rikard Falkebornf9772842020-09-22 21:26:55 +0200693static const struct resource wm831x_ldo1_resources[] = {
Mark Brownd2bedfe2009-07-27 14:45:52 +0100694 {
695 .start = WM831X_LDO1_CONTROL,
696 .end = WM831X_LDO1_SLEEP_CONTROL,
Mark Brown56560982012-08-07 19:42:47 +0100697 .flags = IORESOURCE_REG,
Mark Brownd2bedfe2009-07-27 14:45:52 +0100698 },
Zhen Lei3da286a2021-06-01 15:00:09 +0800699 DEFINE_RES_IRQ_NAMED(WM831X_IRQ_UV_LDO1, "UV"),
Mark Brownd2bedfe2009-07-27 14:45:52 +0100700};
701
Rikard Falkebornf9772842020-09-22 21:26:55 +0200702static const struct resource wm831x_ldo2_resources[] = {
Mark Brownd2bedfe2009-07-27 14:45:52 +0100703 {
704 .start = WM831X_LDO2_CONTROL,
705 .end = WM831X_LDO2_SLEEP_CONTROL,
Mark Brown56560982012-08-07 19:42:47 +0100706 .flags = IORESOURCE_REG,
Mark Brownd2bedfe2009-07-27 14:45:52 +0100707 },
Zhen Lei3da286a2021-06-01 15:00:09 +0800708 DEFINE_RES_IRQ_NAMED(WM831X_IRQ_UV_LDO2, "UV"),
Mark Brownd2bedfe2009-07-27 14:45:52 +0100709};
710
Rikard Falkebornf9772842020-09-22 21:26:55 +0200711static const struct resource wm831x_ldo3_resources[] = {
Mark Brownd2bedfe2009-07-27 14:45:52 +0100712 {
713 .start = WM831X_LDO3_CONTROL,
714 .end = WM831X_LDO3_SLEEP_CONTROL,
Mark Brown56560982012-08-07 19:42:47 +0100715 .flags = IORESOURCE_REG,
Mark Brownd2bedfe2009-07-27 14:45:52 +0100716 },
Zhen Lei3da286a2021-06-01 15:00:09 +0800717 DEFINE_RES_IRQ_NAMED(WM831X_IRQ_UV_LDO3, "UV"),
Mark Brownd2bedfe2009-07-27 14:45:52 +0100718};
719
Rikard Falkebornf9772842020-09-22 21:26:55 +0200720static const struct resource wm831x_ldo4_resources[] = {
Mark Brownd2bedfe2009-07-27 14:45:52 +0100721 {
722 .start = WM831X_LDO4_CONTROL,
723 .end = WM831X_LDO4_SLEEP_CONTROL,
Mark Brown56560982012-08-07 19:42:47 +0100724 .flags = IORESOURCE_REG,
Mark Brownd2bedfe2009-07-27 14:45:52 +0100725 },
Zhen Lei3da286a2021-06-01 15:00:09 +0800726 DEFINE_RES_IRQ_NAMED(WM831X_IRQ_UV_LDO4, "UV"),
Mark Brownd2bedfe2009-07-27 14:45:52 +0100727};
728
Rikard Falkebornf9772842020-09-22 21:26:55 +0200729static const struct resource wm831x_ldo5_resources[] = {
Mark Brownd2bedfe2009-07-27 14:45:52 +0100730 {
731 .start = WM831X_LDO5_CONTROL,
732 .end = WM831X_LDO5_SLEEP_CONTROL,
Mark Brown56560982012-08-07 19:42:47 +0100733 .flags = IORESOURCE_REG,
Mark Brownd2bedfe2009-07-27 14:45:52 +0100734 },
Zhen Lei3da286a2021-06-01 15:00:09 +0800735 DEFINE_RES_IRQ_NAMED(WM831X_IRQ_UV_LDO5, "UV"),
Mark Brownd2bedfe2009-07-27 14:45:52 +0100736};
737
Rikard Falkebornf9772842020-09-22 21:26:55 +0200738static const struct resource wm831x_ldo6_resources[] = {
Mark Brownd2bedfe2009-07-27 14:45:52 +0100739 {
740 .start = WM831X_LDO6_CONTROL,
741 .end = WM831X_LDO6_SLEEP_CONTROL,
Mark Brown56560982012-08-07 19:42:47 +0100742 .flags = IORESOURCE_REG,
Mark Brownd2bedfe2009-07-27 14:45:52 +0100743 },
Zhen Lei3da286a2021-06-01 15:00:09 +0800744 DEFINE_RES_IRQ_NAMED(WM831X_IRQ_UV_LDO6, "UV"),
Mark Brownd2bedfe2009-07-27 14:45:52 +0100745};
746
Rikard Falkebornf9772842020-09-22 21:26:55 +0200747static const struct resource wm831x_ldo7_resources[] = {
Mark Brownd2bedfe2009-07-27 14:45:52 +0100748 {
749 .start = WM831X_LDO7_CONTROL,
750 .end = WM831X_LDO7_SLEEP_CONTROL,
Mark Brown56560982012-08-07 19:42:47 +0100751 .flags = IORESOURCE_REG,
Mark Brownd2bedfe2009-07-27 14:45:52 +0100752 },
Zhen Lei3da286a2021-06-01 15:00:09 +0800753 DEFINE_RES_IRQ_NAMED(WM831X_IRQ_UV_LDO7, "UV"),
Mark Brownd2bedfe2009-07-27 14:45:52 +0100754};
755
Rikard Falkebornf9772842020-09-22 21:26:55 +0200756static const struct resource wm831x_ldo8_resources[] = {
Mark Brownd2bedfe2009-07-27 14:45:52 +0100757 {
758 .start = WM831X_LDO8_CONTROL,
759 .end = WM831X_LDO8_SLEEP_CONTROL,
Mark Brown56560982012-08-07 19:42:47 +0100760 .flags = IORESOURCE_REG,
Mark Brownd2bedfe2009-07-27 14:45:52 +0100761 },
Zhen Lei3da286a2021-06-01 15:00:09 +0800762 DEFINE_RES_IRQ_NAMED(WM831X_IRQ_UV_LDO8, "UV"),
Mark Brownd2bedfe2009-07-27 14:45:52 +0100763};
764
Rikard Falkebornf9772842020-09-22 21:26:55 +0200765static const struct resource wm831x_ldo9_resources[] = {
Mark Brownd2bedfe2009-07-27 14:45:52 +0100766 {
767 .start = WM831X_LDO9_CONTROL,
768 .end = WM831X_LDO9_SLEEP_CONTROL,
Mark Brown56560982012-08-07 19:42:47 +0100769 .flags = IORESOURCE_REG,
Mark Brownd2bedfe2009-07-27 14:45:52 +0100770 },
Zhen Lei3da286a2021-06-01 15:00:09 +0800771 DEFINE_RES_IRQ_NAMED(WM831X_IRQ_UV_LDO9, "UV"),
Mark Brownd2bedfe2009-07-27 14:45:52 +0100772};
773
Rikard Falkebornf9772842020-09-22 21:26:55 +0200774static const struct resource wm831x_ldo10_resources[] = {
Mark Brownd2bedfe2009-07-27 14:45:52 +0100775 {
776 .start = WM831X_LDO10_CONTROL,
777 .end = WM831X_LDO10_SLEEP_CONTROL,
Mark Brown56560982012-08-07 19:42:47 +0100778 .flags = IORESOURCE_REG,
Mark Brownd2bedfe2009-07-27 14:45:52 +0100779 },
Zhen Lei3da286a2021-06-01 15:00:09 +0800780 DEFINE_RES_IRQ_NAMED(WM831X_IRQ_UV_LDO10, "UV"),
Mark Brownd2bedfe2009-07-27 14:45:52 +0100781};
782
Rikard Falkebornf9772842020-09-22 21:26:55 +0200783static const struct resource wm831x_ldo11_resources[] = {
Mark Brownd2bedfe2009-07-27 14:45:52 +0100784 {
785 .start = WM831X_LDO11_ON_CONTROL,
786 .end = WM831X_LDO11_SLEEP_CONTROL,
Mark Brown56560982012-08-07 19:42:47 +0100787 .flags = IORESOURCE_REG,
Mark Brownd2bedfe2009-07-27 14:45:52 +0100788 },
789};
790
Rikard Falkebornf9772842020-09-22 21:26:55 +0200791static const struct resource wm831x_on_resources[] = {
Zhen Lei3da286a2021-06-01 15:00:09 +0800792 DEFINE_RES_IRQ(WM831X_IRQ_ON),
Mark Brownd2bedfe2009-07-27 14:45:52 +0100793};
794
795
Rikard Falkebornf9772842020-09-22 21:26:55 +0200796static const struct resource wm831x_power_resources[] = {
Zhen Lei3da286a2021-06-01 15:00:09 +0800797 DEFINE_RES_IRQ_NAMED(WM831X_IRQ_PPM_SYSLO, "SYSLO"),
798 DEFINE_RES_IRQ_NAMED(WM831X_IRQ_PPM_PWR_SRC, "PWR SRC"),
799 DEFINE_RES_IRQ_NAMED(WM831X_IRQ_PPM_USB_CURR, "USB CURR"),
800 DEFINE_RES_IRQ_NAMED(WM831X_IRQ_CHG_BATT_HOT, "BATT HOT"),
801 DEFINE_RES_IRQ_NAMED(WM831X_IRQ_CHG_BATT_COLD, "BATT COLD"),
802 DEFINE_RES_IRQ_NAMED(WM831X_IRQ_CHG_BATT_FAIL, "BATT FAIL"),
803 DEFINE_RES_IRQ_NAMED(WM831X_IRQ_CHG_OV, "OV"),
804 DEFINE_RES_IRQ_NAMED(WM831X_IRQ_CHG_END, "END"),
805 DEFINE_RES_IRQ_NAMED(WM831X_IRQ_CHG_TO, "TO"),
806 DEFINE_RES_IRQ_NAMED(WM831X_IRQ_CHG_MODE, "MODE"),
807 DEFINE_RES_IRQ_NAMED(WM831X_IRQ_CHG_START, "START"),
Mark Brownd2bedfe2009-07-27 14:45:52 +0100808};
809
Rikard Falkebornf9772842020-09-22 21:26:55 +0200810static const struct resource wm831x_rtc_resources[] = {
Zhen Lei3da286a2021-06-01 15:00:09 +0800811 DEFINE_RES_IRQ_NAMED(WM831X_IRQ_RTC_PER, "PER"),
812 DEFINE_RES_IRQ_NAMED(WM831X_IRQ_RTC_ALM, "ALM"),
Mark Brownd2bedfe2009-07-27 14:45:52 +0100813};
814
Rikard Falkebornf9772842020-09-22 21:26:55 +0200815static const struct resource wm831x_status1_resources[] = {
Mark Brownd2bedfe2009-07-27 14:45:52 +0100816 {
817 .start = WM831X_STATUS_LED_1,
818 .end = WM831X_STATUS_LED_1,
Mark Brown56560982012-08-07 19:42:47 +0100819 .flags = IORESOURCE_REG,
Mark Brownd2bedfe2009-07-27 14:45:52 +0100820 },
821};
822
Rikard Falkebornf9772842020-09-22 21:26:55 +0200823static const struct resource wm831x_status2_resources[] = {
Mark Brownd2bedfe2009-07-27 14:45:52 +0100824 {
825 .start = WM831X_STATUS_LED_2,
826 .end = WM831X_STATUS_LED_2,
Mark Brown56560982012-08-07 19:42:47 +0100827 .flags = IORESOURCE_REG,
Mark Brownd2bedfe2009-07-27 14:45:52 +0100828 },
829};
830
Rikard Falkebornf9772842020-09-22 21:26:55 +0200831static const struct resource wm831x_touch_resources[] = {
Zhen Lei3da286a2021-06-01 15:00:09 +0800832 DEFINE_RES_IRQ_NAMED(WM831X_IRQ_TCHPD, "TCHPD"),
833 DEFINE_RES_IRQ_NAMED(WM831X_IRQ_TCHDATA, "TCHDATA"),
Mark Brownd2bedfe2009-07-27 14:45:52 +0100834};
835
Rikard Falkebornf9772842020-09-22 21:26:55 +0200836static const struct resource wm831x_wdt_resources[] = {
Zhen Lei3da286a2021-06-01 15:00:09 +0800837 DEFINE_RES_IRQ(WM831X_IRQ_WDOG_TO),
Mark Brownd2bedfe2009-07-27 14:45:52 +0100838};
839
Geert Uytterhoevenad59de42013-11-18 14:33:04 +0100840static const struct mfd_cell wm8310_devs[] = {
Mark Brownd2bedfe2009-07-27 14:45:52 +0100841 {
Mark Brownc26964e2009-10-01 15:41:06 +0100842 .name = "wm831x-backup",
843 },
844 {
Mark Brownd2bedfe2009-07-27 14:45:52 +0100845 .name = "wm831x-buckv",
846 .id = 1,
847 .num_resources = ARRAY_SIZE(wm831x_dcdc1_resources),
848 .resources = wm831x_dcdc1_resources,
849 },
850 {
851 .name = "wm831x-buckv",
852 .id = 2,
853 .num_resources = ARRAY_SIZE(wm831x_dcdc2_resources),
854 .resources = wm831x_dcdc2_resources,
855 },
856 {
857 .name = "wm831x-buckp",
858 .id = 3,
859 .num_resources = ARRAY_SIZE(wm831x_dcdc3_resources),
860 .resources = wm831x_dcdc3_resources,
861 },
862 {
863 .name = "wm831x-boostp",
864 .id = 4,
865 .num_resources = ARRAY_SIZE(wm831x_dcdc4_resources),
866 .resources = wm831x_dcdc4_resources,
867 },
868 {
Mark Browna5e06782011-06-24 12:17:07 +0100869 .name = "wm831x-clk",
870 },
871 {
Mark Brownd2bedfe2009-07-27 14:45:52 +0100872 .name = "wm831x-epe",
873 .id = 1,
874 },
875 {
876 .name = "wm831x-epe",
877 .id = 2,
878 },
879 {
880 .name = "wm831x-gpio",
881 .num_resources = ARRAY_SIZE(wm831x_gpio_resources),
882 .resources = wm831x_gpio_resources,
883 },
884 {
885 .name = "wm831x-hwmon",
886 },
887 {
888 .name = "wm831x-isink",
889 .id = 1,
890 .num_resources = ARRAY_SIZE(wm831x_isink1_resources),
891 .resources = wm831x_isink1_resources,
892 },
893 {
894 .name = "wm831x-isink",
895 .id = 2,
896 .num_resources = ARRAY_SIZE(wm831x_isink2_resources),
897 .resources = wm831x_isink2_resources,
898 },
899 {
900 .name = "wm831x-ldo",
901 .id = 1,
902 .num_resources = ARRAY_SIZE(wm831x_ldo1_resources),
903 .resources = wm831x_ldo1_resources,
904 },
905 {
906 .name = "wm831x-ldo",
907 .id = 2,
908 .num_resources = ARRAY_SIZE(wm831x_ldo2_resources),
909 .resources = wm831x_ldo2_resources,
910 },
911 {
912 .name = "wm831x-ldo",
913 .id = 3,
914 .num_resources = ARRAY_SIZE(wm831x_ldo3_resources),
915 .resources = wm831x_ldo3_resources,
916 },
917 {
918 .name = "wm831x-ldo",
919 .id = 4,
920 .num_resources = ARRAY_SIZE(wm831x_ldo4_resources),
921 .resources = wm831x_ldo4_resources,
922 },
923 {
924 .name = "wm831x-ldo",
925 .id = 5,
926 .num_resources = ARRAY_SIZE(wm831x_ldo5_resources),
927 .resources = wm831x_ldo5_resources,
928 },
929 {
930 .name = "wm831x-ldo",
931 .id = 6,
932 .num_resources = ARRAY_SIZE(wm831x_ldo6_resources),
933 .resources = wm831x_ldo6_resources,
934 },
935 {
936 .name = "wm831x-aldo",
937 .id = 7,
938 .num_resources = ARRAY_SIZE(wm831x_ldo7_resources),
939 .resources = wm831x_ldo7_resources,
940 },
941 {
942 .name = "wm831x-aldo",
943 .id = 8,
944 .num_resources = ARRAY_SIZE(wm831x_ldo8_resources),
945 .resources = wm831x_ldo8_resources,
946 },
947 {
948 .name = "wm831x-aldo",
949 .id = 9,
950 .num_resources = ARRAY_SIZE(wm831x_ldo9_resources),
951 .resources = wm831x_ldo9_resources,
952 },
953 {
954 .name = "wm831x-aldo",
955 .id = 10,
956 .num_resources = ARRAY_SIZE(wm831x_ldo10_resources),
957 .resources = wm831x_ldo10_resources,
958 },
959 {
960 .name = "wm831x-alive-ldo",
961 .id = 11,
962 .num_resources = ARRAY_SIZE(wm831x_ldo11_resources),
963 .resources = wm831x_ldo11_resources,
964 },
965 {
966 .name = "wm831x-on",
967 .num_resources = ARRAY_SIZE(wm831x_on_resources),
968 .resources = wm831x_on_resources,
969 },
970 {
971 .name = "wm831x-power",
972 .num_resources = ARRAY_SIZE(wm831x_power_resources),
973 .resources = wm831x_power_resources,
974 },
975 {
Mark Brownd2bedfe2009-07-27 14:45:52 +0100976 .name = "wm831x-status",
977 .id = 1,
978 .num_resources = ARRAY_SIZE(wm831x_status1_resources),
979 .resources = wm831x_status1_resources,
980 },
981 {
982 .name = "wm831x-status",
983 .id = 2,
984 .num_resources = ARRAY_SIZE(wm831x_status2_resources),
985 .resources = wm831x_status2_resources,
986 },
987 {
988 .name = "wm831x-watchdog",
989 .num_resources = ARRAY_SIZE(wm831x_wdt_resources),
990 .resources = wm831x_wdt_resources,
991 },
992};
993
Geert Uytterhoevenad59de42013-11-18 14:33:04 +0100994static const struct mfd_cell wm8311_devs[] = {
Mark Brownd2bedfe2009-07-27 14:45:52 +0100995 {
Mark Brownc26964e2009-10-01 15:41:06 +0100996 .name = "wm831x-backup",
997 },
998 {
Mark Brownd2bedfe2009-07-27 14:45:52 +0100999 .name = "wm831x-buckv",
1000 .id = 1,
1001 .num_resources = ARRAY_SIZE(wm831x_dcdc1_resources),
1002 .resources = wm831x_dcdc1_resources,
1003 },
1004 {
1005 .name = "wm831x-buckv",
1006 .id = 2,
1007 .num_resources = ARRAY_SIZE(wm831x_dcdc2_resources),
1008 .resources = wm831x_dcdc2_resources,
1009 },
1010 {
1011 .name = "wm831x-buckp",
1012 .id = 3,
1013 .num_resources = ARRAY_SIZE(wm831x_dcdc3_resources),
1014 .resources = wm831x_dcdc3_resources,
1015 },
1016 {
1017 .name = "wm831x-boostp",
1018 .id = 4,
1019 .num_resources = ARRAY_SIZE(wm831x_dcdc4_resources),
1020 .resources = wm831x_dcdc4_resources,
1021 },
1022 {
Mark Browna5e06782011-06-24 12:17:07 +01001023 .name = "wm831x-clk",
1024 },
1025 {
Mark Brownd2bedfe2009-07-27 14:45:52 +01001026 .name = "wm831x-epe",
1027 .id = 1,
1028 },
1029 {
1030 .name = "wm831x-epe",
1031 .id = 2,
1032 },
1033 {
1034 .name = "wm831x-gpio",
1035 .num_resources = ARRAY_SIZE(wm831x_gpio_resources),
1036 .resources = wm831x_gpio_resources,
1037 },
1038 {
1039 .name = "wm831x-hwmon",
1040 },
1041 {
1042 .name = "wm831x-isink",
1043 .id = 1,
1044 .num_resources = ARRAY_SIZE(wm831x_isink1_resources),
1045 .resources = wm831x_isink1_resources,
1046 },
1047 {
1048 .name = "wm831x-isink",
1049 .id = 2,
1050 .num_resources = ARRAY_SIZE(wm831x_isink2_resources),
1051 .resources = wm831x_isink2_resources,
1052 },
1053 {
1054 .name = "wm831x-ldo",
1055 .id = 1,
1056 .num_resources = ARRAY_SIZE(wm831x_ldo1_resources),
1057 .resources = wm831x_ldo1_resources,
1058 },
1059 {
1060 .name = "wm831x-ldo",
1061 .id = 2,
1062 .num_resources = ARRAY_SIZE(wm831x_ldo2_resources),
1063 .resources = wm831x_ldo2_resources,
1064 },
1065 {
1066 .name = "wm831x-ldo",
1067 .id = 3,
1068 .num_resources = ARRAY_SIZE(wm831x_ldo3_resources),
1069 .resources = wm831x_ldo3_resources,
1070 },
1071 {
1072 .name = "wm831x-ldo",
1073 .id = 4,
1074 .num_resources = ARRAY_SIZE(wm831x_ldo4_resources),
1075 .resources = wm831x_ldo4_resources,
1076 },
1077 {
1078 .name = "wm831x-ldo",
1079 .id = 5,
1080 .num_resources = ARRAY_SIZE(wm831x_ldo5_resources),
1081 .resources = wm831x_ldo5_resources,
1082 },
1083 {
1084 .name = "wm831x-aldo",
1085 .id = 7,
1086 .num_resources = ARRAY_SIZE(wm831x_ldo7_resources),
1087 .resources = wm831x_ldo7_resources,
1088 },
1089 {
1090 .name = "wm831x-alive-ldo",
1091 .id = 11,
1092 .num_resources = ARRAY_SIZE(wm831x_ldo11_resources),
1093 .resources = wm831x_ldo11_resources,
1094 },
1095 {
1096 .name = "wm831x-on",
1097 .num_resources = ARRAY_SIZE(wm831x_on_resources),
1098 .resources = wm831x_on_resources,
1099 },
1100 {
1101 .name = "wm831x-power",
1102 .num_resources = ARRAY_SIZE(wm831x_power_resources),
1103 .resources = wm831x_power_resources,
1104 },
1105 {
Mark Brownd2bedfe2009-07-27 14:45:52 +01001106 .name = "wm831x-status",
1107 .id = 1,
1108 .num_resources = ARRAY_SIZE(wm831x_status1_resources),
1109 .resources = wm831x_status1_resources,
1110 },
1111 {
1112 .name = "wm831x-status",
1113 .id = 2,
1114 .num_resources = ARRAY_SIZE(wm831x_status2_resources),
1115 .resources = wm831x_status2_resources,
1116 },
1117 {
Mark Brownd2bedfe2009-07-27 14:45:52 +01001118 .name = "wm831x-watchdog",
1119 .num_resources = ARRAY_SIZE(wm831x_wdt_resources),
1120 .resources = wm831x_wdt_resources,
1121 },
1122};
1123
Geert Uytterhoevenad59de42013-11-18 14:33:04 +01001124static const struct mfd_cell wm8312_devs[] = {
Mark Brownd2bedfe2009-07-27 14:45:52 +01001125 {
Mark Brownc26964e2009-10-01 15:41:06 +01001126 .name = "wm831x-backup",
1127 },
1128 {
Mark Brownd2bedfe2009-07-27 14:45:52 +01001129 .name = "wm831x-buckv",
1130 .id = 1,
1131 .num_resources = ARRAY_SIZE(wm831x_dcdc1_resources),
1132 .resources = wm831x_dcdc1_resources,
1133 },
1134 {
1135 .name = "wm831x-buckv",
1136 .id = 2,
1137 .num_resources = ARRAY_SIZE(wm831x_dcdc2_resources),
1138 .resources = wm831x_dcdc2_resources,
1139 },
1140 {
1141 .name = "wm831x-buckp",
1142 .id = 3,
1143 .num_resources = ARRAY_SIZE(wm831x_dcdc3_resources),
1144 .resources = wm831x_dcdc3_resources,
1145 },
1146 {
1147 .name = "wm831x-boostp",
1148 .id = 4,
1149 .num_resources = ARRAY_SIZE(wm831x_dcdc4_resources),
1150 .resources = wm831x_dcdc4_resources,
1151 },
1152 {
Mark Browna5e06782011-06-24 12:17:07 +01001153 .name = "wm831x-clk",
1154 },
1155 {
Mark Brownd2bedfe2009-07-27 14:45:52 +01001156 .name = "wm831x-epe",
1157 .id = 1,
1158 },
1159 {
1160 .name = "wm831x-epe",
1161 .id = 2,
1162 },
1163 {
1164 .name = "wm831x-gpio",
1165 .num_resources = ARRAY_SIZE(wm831x_gpio_resources),
1166 .resources = wm831x_gpio_resources,
1167 },
1168 {
1169 .name = "wm831x-hwmon",
1170 },
1171 {
1172 .name = "wm831x-isink",
1173 .id = 1,
1174 .num_resources = ARRAY_SIZE(wm831x_isink1_resources),
1175 .resources = wm831x_isink1_resources,
1176 },
1177 {
1178 .name = "wm831x-isink",
1179 .id = 2,
1180 .num_resources = ARRAY_SIZE(wm831x_isink2_resources),
1181 .resources = wm831x_isink2_resources,
1182 },
1183 {
1184 .name = "wm831x-ldo",
1185 .id = 1,
1186 .num_resources = ARRAY_SIZE(wm831x_ldo1_resources),
1187 .resources = wm831x_ldo1_resources,
1188 },
1189 {
1190 .name = "wm831x-ldo",
1191 .id = 2,
1192 .num_resources = ARRAY_SIZE(wm831x_ldo2_resources),
1193 .resources = wm831x_ldo2_resources,
1194 },
1195 {
1196 .name = "wm831x-ldo",
1197 .id = 3,
1198 .num_resources = ARRAY_SIZE(wm831x_ldo3_resources),
1199 .resources = wm831x_ldo3_resources,
1200 },
1201 {
1202 .name = "wm831x-ldo",
1203 .id = 4,
1204 .num_resources = ARRAY_SIZE(wm831x_ldo4_resources),
1205 .resources = wm831x_ldo4_resources,
1206 },
1207 {
1208 .name = "wm831x-ldo",
1209 .id = 5,
1210 .num_resources = ARRAY_SIZE(wm831x_ldo5_resources),
1211 .resources = wm831x_ldo5_resources,
1212 },
1213 {
1214 .name = "wm831x-ldo",
1215 .id = 6,
1216 .num_resources = ARRAY_SIZE(wm831x_ldo6_resources),
1217 .resources = wm831x_ldo6_resources,
1218 },
1219 {
1220 .name = "wm831x-aldo",
1221 .id = 7,
1222 .num_resources = ARRAY_SIZE(wm831x_ldo7_resources),
1223 .resources = wm831x_ldo7_resources,
1224 },
1225 {
1226 .name = "wm831x-aldo",
1227 .id = 8,
1228 .num_resources = ARRAY_SIZE(wm831x_ldo8_resources),
1229 .resources = wm831x_ldo8_resources,
1230 },
1231 {
1232 .name = "wm831x-aldo",
1233 .id = 9,
1234 .num_resources = ARRAY_SIZE(wm831x_ldo9_resources),
1235 .resources = wm831x_ldo9_resources,
1236 },
1237 {
1238 .name = "wm831x-aldo",
1239 .id = 10,
1240 .num_resources = ARRAY_SIZE(wm831x_ldo10_resources),
1241 .resources = wm831x_ldo10_resources,
1242 },
1243 {
1244 .name = "wm831x-alive-ldo",
1245 .id = 11,
1246 .num_resources = ARRAY_SIZE(wm831x_ldo11_resources),
1247 .resources = wm831x_ldo11_resources,
1248 },
1249 {
1250 .name = "wm831x-on",
1251 .num_resources = ARRAY_SIZE(wm831x_on_resources),
1252 .resources = wm831x_on_resources,
1253 },
1254 {
1255 .name = "wm831x-power",
1256 .num_resources = ARRAY_SIZE(wm831x_power_resources),
1257 .resources = wm831x_power_resources,
1258 },
1259 {
Mark Brownd2bedfe2009-07-27 14:45:52 +01001260 .name = "wm831x-status",
1261 .id = 1,
1262 .num_resources = ARRAY_SIZE(wm831x_status1_resources),
1263 .resources = wm831x_status1_resources,
1264 },
1265 {
1266 .name = "wm831x-status",
1267 .id = 2,
1268 .num_resources = ARRAY_SIZE(wm831x_status2_resources),
1269 .resources = wm831x_status2_resources,
1270 },
1271 {
Mark Brownd2bedfe2009-07-27 14:45:52 +01001272 .name = "wm831x-watchdog",
1273 .num_resources = ARRAY_SIZE(wm831x_wdt_resources),
1274 .resources = wm831x_wdt_resources,
1275 },
1276};
1277
Geert Uytterhoevenad59de42013-11-18 14:33:04 +01001278static const struct mfd_cell wm8320_devs[] = {
Mark Brownd4e0a892009-10-01 15:41:07 +01001279 {
1280 .name = "wm831x-backup",
1281 },
1282 {
1283 .name = "wm831x-buckv",
1284 .id = 1,
1285 .num_resources = ARRAY_SIZE(wm831x_dcdc1_resources),
1286 .resources = wm831x_dcdc1_resources,
1287 },
1288 {
1289 .name = "wm831x-buckv",
1290 .id = 2,
1291 .num_resources = ARRAY_SIZE(wm831x_dcdc2_resources),
1292 .resources = wm831x_dcdc2_resources,
1293 },
1294 {
1295 .name = "wm831x-buckp",
1296 .id = 3,
1297 .num_resources = ARRAY_SIZE(wm831x_dcdc3_resources),
1298 .resources = wm831x_dcdc3_resources,
1299 },
1300 {
1301 .name = "wm831x-buckp",
1302 .id = 4,
1303 .num_resources = ARRAY_SIZE(wm8320_dcdc4_buck_resources),
1304 .resources = wm8320_dcdc4_buck_resources,
1305 },
1306 {
Mark Browna5e06782011-06-24 12:17:07 +01001307 .name = "wm831x-clk",
1308 },
1309 {
Mark Brownd4e0a892009-10-01 15:41:07 +01001310 .name = "wm831x-gpio",
1311 .num_resources = ARRAY_SIZE(wm831x_gpio_resources),
1312 .resources = wm831x_gpio_resources,
1313 },
1314 {
1315 .name = "wm831x-hwmon",
1316 },
1317 {
1318 .name = "wm831x-ldo",
1319 .id = 1,
1320 .num_resources = ARRAY_SIZE(wm831x_ldo1_resources),
1321 .resources = wm831x_ldo1_resources,
1322 },
1323 {
1324 .name = "wm831x-ldo",
1325 .id = 2,
1326 .num_resources = ARRAY_SIZE(wm831x_ldo2_resources),
1327 .resources = wm831x_ldo2_resources,
1328 },
1329 {
1330 .name = "wm831x-ldo",
1331 .id = 3,
1332 .num_resources = ARRAY_SIZE(wm831x_ldo3_resources),
1333 .resources = wm831x_ldo3_resources,
1334 },
1335 {
1336 .name = "wm831x-ldo",
1337 .id = 4,
1338 .num_resources = ARRAY_SIZE(wm831x_ldo4_resources),
1339 .resources = wm831x_ldo4_resources,
1340 },
1341 {
1342 .name = "wm831x-ldo",
1343 .id = 5,
1344 .num_resources = ARRAY_SIZE(wm831x_ldo5_resources),
1345 .resources = wm831x_ldo5_resources,
1346 },
1347 {
1348 .name = "wm831x-ldo",
1349 .id = 6,
1350 .num_resources = ARRAY_SIZE(wm831x_ldo6_resources),
1351 .resources = wm831x_ldo6_resources,
1352 },
1353 {
1354 .name = "wm831x-aldo",
1355 .id = 7,
1356 .num_resources = ARRAY_SIZE(wm831x_ldo7_resources),
1357 .resources = wm831x_ldo7_resources,
1358 },
1359 {
1360 .name = "wm831x-aldo",
1361 .id = 8,
1362 .num_resources = ARRAY_SIZE(wm831x_ldo8_resources),
1363 .resources = wm831x_ldo8_resources,
1364 },
1365 {
1366 .name = "wm831x-aldo",
1367 .id = 9,
1368 .num_resources = ARRAY_SIZE(wm831x_ldo9_resources),
1369 .resources = wm831x_ldo9_resources,
1370 },
1371 {
1372 .name = "wm831x-aldo",
1373 .id = 10,
1374 .num_resources = ARRAY_SIZE(wm831x_ldo10_resources),
1375 .resources = wm831x_ldo10_resources,
1376 },
1377 {
1378 .name = "wm831x-alive-ldo",
1379 .id = 11,
1380 .num_resources = ARRAY_SIZE(wm831x_ldo11_resources),
1381 .resources = wm831x_ldo11_resources,
1382 },
1383 {
1384 .name = "wm831x-on",
1385 .num_resources = ARRAY_SIZE(wm831x_on_resources),
1386 .resources = wm831x_on_resources,
1387 },
1388 {
Mark Brownd4e0a892009-10-01 15:41:07 +01001389 .name = "wm831x-status",
1390 .id = 1,
1391 .num_resources = ARRAY_SIZE(wm831x_status1_resources),
1392 .resources = wm831x_status1_resources,
1393 },
1394 {
1395 .name = "wm831x-status",
1396 .id = 2,
1397 .num_resources = ARRAY_SIZE(wm831x_status2_resources),
1398 .resources = wm831x_status2_resources,
1399 },
1400 {
1401 .name = "wm831x-watchdog",
1402 .num_resources = ARRAY_SIZE(wm831x_wdt_resources),
1403 .resources = wm831x_wdt_resources,
1404 },
1405};
1406
Geert Uytterhoevenad59de42013-11-18 14:33:04 +01001407static const struct mfd_cell touch_devs[] = {
Mark Brown266a5e02011-06-02 19:18:49 +01001408 {
1409 .name = "wm831x-touch",
1410 .num_resources = ARRAY_SIZE(wm831x_touch_resources),
1411 .resources = wm831x_touch_resources,
1412 },
1413};
1414
Geert Uytterhoevenad59de42013-11-18 14:33:04 +01001415static const struct mfd_cell rtc_devs[] = {
Mark Brownb9d03d92011-06-02 19:18:50 +01001416 {
1417 .name = "wm831x-rtc",
1418 .num_resources = ARRAY_SIZE(wm831x_rtc_resources),
1419 .resources = wm831x_rtc_resources,
1420 },
1421};
Mark Brown266a5e02011-06-02 19:18:49 +01001422
Geert Uytterhoevenad59de42013-11-18 14:33:04 +01001423static const struct mfd_cell backlight_devs[] = {
Mark Brown63aed852009-07-27 14:45:55 +01001424 {
1425 .name = "wm831x-backlight",
1426 },
1427};
1428
Mark Brown1df59812011-06-10 19:28:10 +01001429struct regmap_config wm831x_regmap_config = {
1430 .reg_bits = 16,
1431 .val_bits = 16,
Mark Brown2e47fff2011-07-21 17:30:08 +01001432
Mark Brown7cccbdc2011-10-09 13:38:06 +01001433 .cache_type = REGCACHE_RBTREE,
1434
Mark Brown2e47fff2011-07-21 17:30:08 +01001435 .max_register = WM831X_DBE_CHECK_DATA,
1436 .readable_reg = wm831x_reg_readable,
1437 .writeable_reg = wm831x_reg_writeable,
1438 .volatile_reg = wm831x_reg_volatile,
Mark Brown1df59812011-06-10 19:28:10 +01001439};
1440EXPORT_SYMBOL_GPL(wm831x_regmap_config);
1441
Charles Keepaxf6dd8442017-03-17 10:05:18 +00001442const struct of_device_id wm831x_of_match[] = {
1443 { .compatible = "wlf,wm8310", .data = (void *)WM8310 },
1444 { .compatible = "wlf,wm8311", .data = (void *)WM8311 },
1445 { .compatible = "wlf,wm8312", .data = (void *)WM8312 },
1446 { .compatible = "wlf,wm8320", .data = (void *)WM8320 },
1447 { .compatible = "wlf,wm8321", .data = (void *)WM8321 },
1448 { .compatible = "wlf,wm8325", .data = (void *)WM8325 },
1449 { .compatible = "wlf,wm8326", .data = (void *)WM8326 },
1450 { },
1451};
1452EXPORT_SYMBOL_GPL(wm831x_of_match);
1453
Mark Brownd2bedfe2009-07-27 14:45:52 +01001454/*
1455 * Instantiate the generic non-control parts of the device.
1456 */
Charles Keepaxf6dd8442017-03-17 10:05:18 +00001457int wm831x_device_init(struct wm831x *wm831x, int irq)
Mark Brownd2bedfe2009-07-27 14:45:52 +01001458{
Charles Keepaxf6dd8442017-03-17 10:05:18 +00001459 struct wm831x_pdata *pdata = &wm831x->pdata;
Mark Browneb503dc2011-06-02 19:18:48 +01001460 int rev, wm831x_num;
Mark Brownd2bedfe2009-07-27 14:45:52 +01001461 enum wm831x_parent parent;
Mark Brown0b14c222011-04-04 11:04:42 +09001462 int ret, i;
Mark Brownd2bedfe2009-07-27 14:45:52 +01001463
1464 mutex_init(&wm831x->io_lock);
1465 mutex_init(&wm831x->key_lock);
1466 dev_set_drvdata(wm831x->dev, wm831x);
Javier Martinez Canillas16dfd102015-09-14 11:07:56 +02001467
Charles Keepaxf6dd8442017-03-17 10:05:18 +00001468 wm831x->soft_shutdown = pdata->soft_shutdown;
Mark Brownd2bedfe2009-07-27 14:45:52 +01001469
1470 ret = wm831x_reg_read(wm831x, WM831X_PARENT_ID);
1471 if (ret < 0) {
1472 dev_err(wm831x->dev, "Failed to read parent ID: %d\n", ret);
Mark Brown130a7032012-01-30 20:08:06 +00001473 goto err;
Mark Brownd2bedfe2009-07-27 14:45:52 +01001474 }
Mark Brownb93cef52010-12-02 16:25:43 +00001475 switch (ret) {
1476 case 0x6204:
1477 case 0x6246:
1478 break;
1479 default:
Mark Brownd2bedfe2009-07-27 14:45:52 +01001480 dev_err(wm831x->dev, "Device is not a WM831x: ID %x\n", ret);
1481 ret = -EINVAL;
Mark Brown130a7032012-01-30 20:08:06 +00001482 goto err;
Mark Brownd2bedfe2009-07-27 14:45:52 +01001483 }
1484
1485 ret = wm831x_reg_read(wm831x, WM831X_REVISION);
1486 if (ret < 0) {
1487 dev_err(wm831x->dev, "Failed to read revision: %d\n", ret);
Mark Brown130a7032012-01-30 20:08:06 +00001488 goto err;
Mark Brownd2bedfe2009-07-27 14:45:52 +01001489 }
1490 rev = (ret & WM831X_PARENT_REV_MASK) >> WM831X_PARENT_REV_SHIFT;
1491
1492 ret = wm831x_reg_read(wm831x, WM831X_RESET_ID);
1493 if (ret < 0) {
1494 dev_err(wm831x->dev, "Failed to read device ID: %d\n", ret);
Mark Brown130a7032012-01-30 20:08:06 +00001495 goto err;
Mark Brownd2bedfe2009-07-27 14:45:52 +01001496 }
1497
Mark Brown894362f2009-10-01 15:41:04 +01001498 /* Some engineering samples do not have the ID set, rely on
1499 * the device being registered correctly.
1500 */
1501 if (ret == 0) {
1502 dev_info(wm831x->dev, "Device is an engineering sample\n");
Charles Keepaxf6dd8442017-03-17 10:05:18 +00001503 ret = wm831x->type;
Mark Brown894362f2009-10-01 15:41:04 +01001504 }
1505
Mark Brownd2bedfe2009-07-27 14:45:52 +01001506 switch (ret) {
Mark Brown894362f2009-10-01 15:41:04 +01001507 case WM8310:
Mark Brownd2bedfe2009-07-27 14:45:52 +01001508 parent = WM8310;
Mark Brown6f2ecaa2009-10-01 15:41:05 +01001509 wm831x->num_gpio = 16;
Mark Brownb03b4d72010-04-08 10:02:39 +02001510 wm831x->charger_irq_wake = 1;
Mark Brownf92e8f82010-02-17 18:45:25 +00001511 if (rev > 0) {
1512 wm831x->has_gpio_ena = 1;
1513 wm831x->has_cs_sts = 1;
1514 }
1515
Mark Brown894362f2009-10-01 15:41:04 +01001516 dev_info(wm831x->dev, "WM8310 revision %c\n", 'A' + rev);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001517 break;
1518
Mark Brown894362f2009-10-01 15:41:04 +01001519 case WM8311:
Mark Brownd2bedfe2009-07-27 14:45:52 +01001520 parent = WM8311;
Mark Brown6f2ecaa2009-10-01 15:41:05 +01001521 wm831x->num_gpio = 16;
Mark Brownb03b4d72010-04-08 10:02:39 +02001522 wm831x->charger_irq_wake = 1;
Mark Brownf92e8f82010-02-17 18:45:25 +00001523 if (rev > 0) {
1524 wm831x->has_gpio_ena = 1;
1525 wm831x->has_cs_sts = 1;
1526 }
1527
Mark Brown894362f2009-10-01 15:41:04 +01001528 dev_info(wm831x->dev, "WM8311 revision %c\n", 'A' + rev);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001529 break;
1530
Mark Brown894362f2009-10-01 15:41:04 +01001531 case WM8312:
Mark Brownd2bedfe2009-07-27 14:45:52 +01001532 parent = WM8312;
Mark Brown6f2ecaa2009-10-01 15:41:05 +01001533 wm831x->num_gpio = 16;
Mark Brownb03b4d72010-04-08 10:02:39 +02001534 wm831x->charger_irq_wake = 1;
Mark Brownf92e8f82010-02-17 18:45:25 +00001535 if (rev > 0) {
1536 wm831x->has_gpio_ena = 1;
1537 wm831x->has_cs_sts = 1;
1538 }
1539
Mark Brown894362f2009-10-01 15:41:04 +01001540 dev_info(wm831x->dev, "WM8312 revision %c\n", 'A' + rev);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001541 break;
1542
Mark Brownd4e0a892009-10-01 15:41:07 +01001543 case WM8320:
1544 parent = WM8320;
1545 wm831x->num_gpio = 12;
1546 dev_info(wm831x->dev, "WM8320 revision %c\n", 'A' + rev);
1547 break;
1548
Mark Brown88913522010-07-21 14:23:37 +01001549 case WM8321:
1550 parent = WM8321;
1551 wm831x->num_gpio = 12;
1552 dev_info(wm831x->dev, "WM8321 revision %c\n", 'A' + rev);
1553 break;
1554
Mark Brown0b315882010-09-28 09:13:39 -07001555 case WM8325:
1556 parent = WM8325;
1557 wm831x->num_gpio = 12;
1558 dev_info(wm831x->dev, "WM8325 revision %c\n", 'A' + rev);
1559 break;
1560
Mark Brown412dc112010-11-24 18:01:41 +00001561 case WM8326:
1562 parent = WM8326;
1563 wm831x->num_gpio = 12;
1564 dev_info(wm831x->dev, "WM8326 revision %c\n", 'A' + rev);
1565 break;
1566
Mark Brownd2bedfe2009-07-27 14:45:52 +01001567 default:
1568 dev_err(wm831x->dev, "Unknown WM831x device %04x\n", ret);
1569 ret = -EINVAL;
Mark Brown130a7032012-01-30 20:08:06 +00001570 goto err;
Mark Brownd2bedfe2009-07-27 14:45:52 +01001571 }
1572
1573 /* This will need revisiting in future but is OK for all
1574 * current parts.
1575 */
Charles Keepaxf6dd8442017-03-17 10:05:18 +00001576 if (parent != wm831x->type)
1577 dev_warn(wm831x->dev, "Device was registered as a WM%x\n",
1578 wm831x->type);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001579
1580 /* Bootstrap the user key */
1581 ret = wm831x_reg_read(wm831x, WM831X_SECURITY_KEY);
1582 if (ret < 0) {
1583 dev_err(wm831x->dev, "Failed to read security key: %d\n", ret);
Mark Brown130a7032012-01-30 20:08:06 +00001584 goto err;
Mark Brownd2bedfe2009-07-27 14:45:52 +01001585 }
1586 if (ret != 0) {
1587 dev_warn(wm831x->dev, "Security key had non-zero value %x\n",
1588 ret);
1589 wm831x_reg_write(wm831x, WM831X_SECURITY_KEY, 0);
1590 }
1591 wm831x->locked = 1;
1592
Charles Keepaxdcb0574b2017-05-15 13:51:24 +01001593 if (pdata->pre_init) {
Mark Brownd2bedfe2009-07-27 14:45:52 +01001594 ret = pdata->pre_init(wm831x);
1595 if (ret != 0) {
1596 dev_err(wm831x->dev, "pre_init() failed: %d\n", ret);
Mark Brown130a7032012-01-30 20:08:06 +00001597 goto err;
Mark Brownd2bedfe2009-07-27 14:45:52 +01001598 }
1599 }
1600
Charles Keepaxdcb0574b2017-05-15 13:51:24 +01001601 for (i = 0; i < ARRAY_SIZE(pdata->gpio_defaults); i++) {
1602 if (!pdata->gpio_defaults[i])
1603 continue;
Mark Brown0b14c222011-04-04 11:04:42 +09001604
Charles Keepaxdcb0574b2017-05-15 13:51:24 +01001605 wm831x_reg_write(wm831x,
1606 WM831X_GPIO1_CONTROL + i,
1607 pdata->gpio_defaults[i] & 0xffff);
Mark Brown0b14c222011-04-04 11:04:42 +09001608 }
1609
Mark Browneb503dc2011-06-02 19:18:48 +01001610 /* Multiply by 10 as we have many subdevices of the same type */
Charles Keepaxdcb0574b2017-05-15 13:51:24 +01001611 if (pdata->wm831x_num)
Mark Browneb503dc2011-06-02 19:18:48 +01001612 wm831x_num = pdata->wm831x_num * 10;
1613 else
1614 wm831x_num = -1;
1615
Mark Brown7d4d0a32009-07-27 14:45:53 +01001616 ret = wm831x_irq_init(wm831x, irq);
1617 if (ret != 0)
Mark Brown130a7032012-01-30 20:08:06 +00001618 goto err;
Mark Brown7d4d0a32009-07-27 14:45:53 +01001619
Mark Browne69b6de2011-06-02 19:18:53 +01001620 wm831x_auxadc_init(wm831x);
Mark Brown473fe732010-02-23 11:08:06 +00001621
Mark Brownd2bedfe2009-07-27 14:45:52 +01001622 /* The core device is up, instantiate the subdevices. */
1623 switch (parent) {
1624 case WM8310:
Mark Browneb503dc2011-06-02 19:18:48 +01001625 ret = mfd_add_devices(wm831x->dev, wm831x_num,
Mark Brownd2bedfe2009-07-27 14:45:52 +01001626 wm8310_devs, ARRAY_SIZE(wm8310_devs),
Mark Brown55692af2012-09-11 15:16:36 +08001627 NULL, 0, NULL);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001628 break;
1629
1630 case WM8311:
Mark Browneb503dc2011-06-02 19:18:48 +01001631 ret = mfd_add_devices(wm831x->dev, wm831x_num,
Mark Brownd2bedfe2009-07-27 14:45:52 +01001632 wm8311_devs, ARRAY_SIZE(wm8311_devs),
Mark Brown55692af2012-09-11 15:16:36 +08001633 NULL, 0, NULL);
Charles Keepaxdcb0574b2017-05-15 13:51:24 +01001634 if (!pdata->disable_touch)
Mark Brown266a5e02011-06-02 19:18:49 +01001635 mfd_add_devices(wm831x->dev, wm831x_num,
1636 touch_devs, ARRAY_SIZE(touch_devs),
Mark Brown55692af2012-09-11 15:16:36 +08001637 NULL, 0, NULL);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001638 break;
1639
1640 case WM8312:
Mark Browneb503dc2011-06-02 19:18:48 +01001641 ret = mfd_add_devices(wm831x->dev, wm831x_num,
Mark Brownd2bedfe2009-07-27 14:45:52 +01001642 wm8312_devs, ARRAY_SIZE(wm8312_devs),
Mark Brown55692af2012-09-11 15:16:36 +08001643 NULL, 0, NULL);
Charles Keepaxdcb0574b2017-05-15 13:51:24 +01001644 if (!pdata->disable_touch)
Mark Brown266a5e02011-06-02 19:18:49 +01001645 mfd_add_devices(wm831x->dev, wm831x_num,
1646 touch_devs, ARRAY_SIZE(touch_devs),
Mark Brown55692af2012-09-11 15:16:36 +08001647 NULL, 0, NULL);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001648 break;
1649
Mark Brownd4e0a892009-10-01 15:41:07 +01001650 case WM8320:
Mark Brown88913522010-07-21 14:23:37 +01001651 case WM8321:
Mark Brown0b315882010-09-28 09:13:39 -07001652 case WM8325:
Mark Brown412dc112010-11-24 18:01:41 +00001653 case WM8326:
Mark Browneb503dc2011-06-02 19:18:48 +01001654 ret = mfd_add_devices(wm831x->dev, wm831x_num,
Mark Brown0b315882010-09-28 09:13:39 -07001655 wm8320_devs, ARRAY_SIZE(wm8320_devs),
Mark Brown55692af2012-09-11 15:16:36 +08001656 NULL, 0, NULL);
Mark Brown0b315882010-09-28 09:13:39 -07001657 break;
1658
Mark Brownd2bedfe2009-07-27 14:45:52 +01001659 default:
1660 /* If this happens the bus probe function is buggy */
1661 BUG();
1662 }
1663
1664 if (ret != 0) {
1665 dev_err(wm831x->dev, "Failed to add children\n");
Mark Brown7d4d0a32009-07-27 14:45:53 +01001666 goto err_irq;
Mark Brownd2bedfe2009-07-27 14:45:52 +01001667 }
1668
Mark Brownb9d03d92011-06-02 19:18:50 +01001669 /* The RTC can only be used if the 32.768kHz crystal is
1670 * enabled; this can't be controlled by software at runtime.
1671 */
1672 ret = wm831x_reg_read(wm831x, WM831X_CLOCK_CONTROL_2);
1673 if (ret < 0) {
1674 dev_err(wm831x->dev, "Failed to read clock status: %d\n", ret);
1675 goto err_irq;
1676 }
1677
1678 if (ret & WM831X_XTAL_ENA) {
1679 ret = mfd_add_devices(wm831x->dev, wm831x_num,
1680 rtc_devs, ARRAY_SIZE(rtc_devs),
Mark Brown55692af2012-09-11 15:16:36 +08001681 NULL, 0, NULL);
Mark Brownb9d03d92011-06-02 19:18:50 +01001682 if (ret != 0) {
1683 dev_err(wm831x->dev, "Failed to add RTC: %d\n", ret);
1684 goto err_irq;
1685 }
1686 } else {
1687 dev_info(wm831x->dev, "32.768kHz clock disabled, no RTC\n");
1688 }
1689
Charles Keepaxdcb0574b2017-05-15 13:51:24 +01001690 if (pdata->backlight) {
Mark Brown63aed852009-07-27 14:45:55 +01001691 /* Treat errors as non-critical */
Mark Browneb503dc2011-06-02 19:18:48 +01001692 ret = mfd_add_devices(wm831x->dev, wm831x_num, backlight_devs,
Mark Brown5fb4d382009-11-11 16:10:22 +00001693 ARRAY_SIZE(backlight_devs), NULL,
Mark Brown55692af2012-09-11 15:16:36 +08001694 0, NULL);
Mark Brown63aed852009-07-27 14:45:55 +01001695 if (ret < 0)
1696 dev_err(wm831x->dev, "Failed to add backlight: %d\n",
1697 ret);
1698 }
1699
Mark Brown6704e512009-07-27 14:45:56 +01001700 wm831x_otp_init(wm831x);
1701
Charles Keepaxdcb0574b2017-05-15 13:51:24 +01001702 if (pdata->post_init) {
Mark Brownd2bedfe2009-07-27 14:45:52 +01001703 ret = pdata->post_init(wm831x);
1704 if (ret != 0) {
1705 dev_err(wm831x->dev, "post_init() failed: %d\n", ret);
Mark Brown7d4d0a32009-07-27 14:45:53 +01001706 goto err_irq;
Mark Brownd2bedfe2009-07-27 14:45:52 +01001707 }
1708 }
1709
1710 return 0;
1711
Mark Brown7d4d0a32009-07-27 14:45:53 +01001712err_irq:
1713 wm831x_irq_exit(wm831x);
Mark Brown130a7032012-01-30 20:08:06 +00001714err:
Mark Brownd2bedfe2009-07-27 14:45:52 +01001715 mfd_remove_devices(wm831x->dev);
Mark Brownd2bedfe2009-07-27 14:45:52 +01001716 return ret;
1717}
1718
Mark Browne5b48682010-10-19 23:57:56 +02001719int wm831x_device_suspend(struct wm831x *wm831x)
Mark Brownb03b4d72010-04-08 10:02:39 +02001720{
1721 int reg, mask;
1722
1723 /* If the charger IRQs are a wake source then make sure we ack
1724 * them even if they're not actively being used (eg, no power
1725 * driver or no IRQ line wired up) then acknowledge the
1726 * interrupts otherwise suspend won't last very long.
1727 */
1728 if (wm831x->charger_irq_wake) {
1729 reg = wm831x_reg_read(wm831x, WM831X_INTERRUPT_STATUS_2_MASK);
1730
1731 mask = WM831X_CHG_BATT_HOT_EINT |
1732 WM831X_CHG_BATT_COLD_EINT |
1733 WM831X_CHG_BATT_FAIL_EINT |
1734 WM831X_CHG_OV_EINT | WM831X_CHG_END_EINT |
1735 WM831X_CHG_TO_EINT | WM831X_CHG_MODE_EINT |
1736 WM831X_CHG_START_EINT;
1737
1738 /* If any of the interrupts are masked read the statuses */
1739 if (reg & mask)
1740 reg = wm831x_reg_read(wm831x,
1741 WM831X_INTERRUPT_STATUS_2);
1742
1743 if (reg & mask) {
1744 dev_info(wm831x->dev,
1745 "Acknowledging masked charger IRQs: %x\n",
1746 reg & mask);
1747 wm831x_reg_write(wm831x, WM831X_INTERRUPT_STATUS_2,
1748 reg & mask);
1749 }
1750 }
1751
1752 return 0;
1753}
1754
Mark Brown523d9cf2011-09-15 18:54:53 +02001755void wm831x_device_shutdown(struct wm831x *wm831x)
1756{
1757 if (wm831x->soft_shutdown) {
1758 dev_info(wm831x->dev, "Initiating shutdown...\n");
1759 wm831x_set_bits(wm831x, WM831X_POWER_STATE, WM831X_CHIP_ON, 0);
1760 }
1761}
1762EXPORT_SYMBOL_GPL(wm831x_device_shutdown);