xref: /openbmc/linux/drivers/mfd/wm831x-core.c (revision f92e8f81)
1d2bedfe7SMark Brown /*
2d2bedfe7SMark Brown  * wm831x-core.c  --  Device access for Wolfson WM831x PMICs
3d2bedfe7SMark Brown  *
4d2bedfe7SMark Brown  * Copyright 2009 Wolfson Microelectronics PLC.
5d2bedfe7SMark Brown  *
6d2bedfe7SMark Brown  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
7d2bedfe7SMark Brown  *
8d2bedfe7SMark Brown  *  This program is free software; you can redistribute  it and/or modify it
9d2bedfe7SMark Brown  *  under  the terms of  the GNU General  Public License as published by the
10d2bedfe7SMark Brown  *  Free Software Foundation;  either version 2 of the  License, or (at your
11d2bedfe7SMark Brown  *  option) any later version.
12d2bedfe7SMark Brown  *
13d2bedfe7SMark Brown  */
14d2bedfe7SMark Brown 
15d2bedfe7SMark Brown #include <linux/kernel.h>
16d2bedfe7SMark Brown #include <linux/module.h>
17d2bedfe7SMark Brown #include <linux/i2c.h>
187e9f9fd4SMark Brown #include <linux/bcd.h>
197e9f9fd4SMark Brown #include <linux/delay.h>
20d2bedfe7SMark Brown #include <linux/mfd/core.h>
21d2bedfe7SMark Brown 
22d2bedfe7SMark Brown #include <linux/mfd/wm831x/core.h>
23d2bedfe7SMark Brown #include <linux/mfd/wm831x/pdata.h>
247d4d0a3eSMark Brown #include <linux/mfd/wm831x/irq.h>
257e9f9fd4SMark Brown #include <linux/mfd/wm831x/auxadc.h>
266704e517SMark Brown #include <linux/mfd/wm831x/otp.h>
27698659d5SMark Brown #include <linux/mfd/wm831x/regulator.h>
28698659d5SMark Brown 
29698659d5SMark Brown /* Current settings - values are 2*2^(reg_val/4) microamps.  These are
30698659d5SMark Brown  * exported since they are used by multiple drivers.
31698659d5SMark Brown  */
327716977bSMark Brown int wm831x_isinkv_values[WM831X_ISINK_MAX_ISEL + 1] = {
33698659d5SMark Brown 	2,
34698659d5SMark Brown 	2,
35698659d5SMark Brown 	3,
36698659d5SMark Brown 	3,
37698659d5SMark Brown 	4,
38698659d5SMark Brown 	5,
39698659d5SMark Brown 	6,
40698659d5SMark Brown 	7,
41698659d5SMark Brown 	8,
42698659d5SMark Brown 	10,
43698659d5SMark Brown 	11,
44698659d5SMark Brown 	13,
45698659d5SMark Brown 	16,
46698659d5SMark Brown 	19,
47698659d5SMark Brown 	23,
48698659d5SMark Brown 	27,
49698659d5SMark Brown 	32,
50698659d5SMark Brown 	38,
51698659d5SMark Brown 	45,
52698659d5SMark Brown 	54,
53698659d5SMark Brown 	64,
54698659d5SMark Brown 	76,
55698659d5SMark Brown 	91,
56698659d5SMark Brown 	108,
57698659d5SMark Brown 	128,
58698659d5SMark Brown 	152,
59698659d5SMark Brown 	181,
60698659d5SMark Brown 	215,
61698659d5SMark Brown 	256,
62698659d5SMark Brown 	304,
63698659d5SMark Brown 	362,
64698659d5SMark Brown 	431,
65698659d5SMark Brown 	512,
66698659d5SMark Brown 	609,
67698659d5SMark Brown 	724,
68698659d5SMark Brown 	861,
69698659d5SMark Brown 	1024,
70698659d5SMark Brown 	1218,
71698659d5SMark Brown 	1448,
72698659d5SMark Brown 	1722,
73698659d5SMark Brown 	2048,
74698659d5SMark Brown 	2435,
75698659d5SMark Brown 	2896,
76698659d5SMark Brown 	3444,
77698659d5SMark Brown 	4096,
78698659d5SMark Brown 	4871,
79698659d5SMark Brown 	5793,
80698659d5SMark Brown 	6889,
81698659d5SMark Brown 	8192,
82698659d5SMark Brown 	9742,
83698659d5SMark Brown 	11585,
84698659d5SMark Brown 	13777,
85698659d5SMark Brown 	16384,
86698659d5SMark Brown 	19484,
87698659d5SMark Brown 	23170,
88698659d5SMark Brown 	27554,
89698659d5SMark Brown };
90698659d5SMark Brown EXPORT_SYMBOL_GPL(wm831x_isinkv_values);
91d2bedfe7SMark Brown 
92d2bedfe7SMark Brown enum wm831x_parent {
93894362f5SMark Brown 	WM8310 = 0x8310,
94894362f5SMark Brown 	WM8311 = 0x8311,
95894362f5SMark Brown 	WM8312 = 0x8312,
96d4e0a89eSMark Brown 	WM8320 = 0x8320,
97d2bedfe7SMark Brown };
98d2bedfe7SMark Brown 
99d2bedfe7SMark Brown static int wm831x_reg_locked(struct wm831x *wm831x, unsigned short reg)
100d2bedfe7SMark Brown {
101d2bedfe7SMark Brown 	if (!wm831x->locked)
102d2bedfe7SMark Brown 		return 0;
103d2bedfe7SMark Brown 
104d2bedfe7SMark Brown 	switch (reg) {
105d2bedfe7SMark Brown 	case WM831X_WATCHDOG:
106d2bedfe7SMark Brown 	case WM831X_DC4_CONTROL:
107d2bedfe7SMark Brown 	case WM831X_ON_PIN_CONTROL:
108d2bedfe7SMark Brown 	case WM831X_BACKUP_CHARGER_CONTROL:
109d2bedfe7SMark Brown 	case WM831X_CHARGER_CONTROL_1:
110d2bedfe7SMark Brown 	case WM831X_CHARGER_CONTROL_2:
111d2bedfe7SMark Brown 		return 1;
112d2bedfe7SMark Brown 
113d2bedfe7SMark Brown 	default:
114d2bedfe7SMark Brown 		return 0;
115d2bedfe7SMark Brown 	}
116d2bedfe7SMark Brown }
117d2bedfe7SMark Brown 
118d2bedfe7SMark Brown /**
119d2bedfe7SMark Brown  * wm831x_reg_unlock: Unlock user keyed registers
120d2bedfe7SMark Brown  *
121d2bedfe7SMark Brown  * The WM831x has a user key preventing writes to particularly
122d2bedfe7SMark Brown  * critical registers.  This function locks those registers,
123d2bedfe7SMark Brown  * allowing writes to them.
124d2bedfe7SMark Brown  */
125d2bedfe7SMark Brown void wm831x_reg_lock(struct wm831x *wm831x)
126d2bedfe7SMark Brown {
127d2bedfe7SMark Brown 	int ret;
128d2bedfe7SMark Brown 
129d2bedfe7SMark Brown 	ret = wm831x_reg_write(wm831x, WM831X_SECURITY_KEY, 0);
130d2bedfe7SMark Brown 	if (ret == 0) {
131d2bedfe7SMark Brown 		dev_vdbg(wm831x->dev, "Registers locked\n");
132d2bedfe7SMark Brown 
133d2bedfe7SMark Brown 		mutex_lock(&wm831x->io_lock);
134d2bedfe7SMark Brown 		WARN_ON(wm831x->locked);
135d2bedfe7SMark Brown 		wm831x->locked = 1;
136d2bedfe7SMark Brown 		mutex_unlock(&wm831x->io_lock);
137d2bedfe7SMark Brown 	} else {
138d2bedfe7SMark Brown 		dev_err(wm831x->dev, "Failed to lock registers: %d\n", ret);
139d2bedfe7SMark Brown 	}
140d2bedfe7SMark Brown 
141d2bedfe7SMark Brown }
142d2bedfe7SMark Brown EXPORT_SYMBOL_GPL(wm831x_reg_lock);
143d2bedfe7SMark Brown 
144d2bedfe7SMark Brown /**
145d2bedfe7SMark Brown  * wm831x_reg_unlock: Unlock user keyed registers
146d2bedfe7SMark Brown  *
147d2bedfe7SMark Brown  * The WM831x has a user key preventing writes to particularly
148d2bedfe7SMark Brown  * critical registers.  This function locks those registers,
149d2bedfe7SMark Brown  * preventing spurious writes.
150d2bedfe7SMark Brown  */
151d2bedfe7SMark Brown int wm831x_reg_unlock(struct wm831x *wm831x)
152d2bedfe7SMark Brown {
153d2bedfe7SMark Brown 	int ret;
154d2bedfe7SMark Brown 
155d2bedfe7SMark Brown 	/* 0x9716 is the value required to unlock the registers */
156d2bedfe7SMark Brown 	ret = wm831x_reg_write(wm831x, WM831X_SECURITY_KEY, 0x9716);
157d2bedfe7SMark Brown 	if (ret == 0) {
158d2bedfe7SMark Brown 		dev_vdbg(wm831x->dev, "Registers unlocked\n");
159d2bedfe7SMark Brown 
160d2bedfe7SMark Brown 		mutex_lock(&wm831x->io_lock);
161d2bedfe7SMark Brown 		WARN_ON(!wm831x->locked);
162d2bedfe7SMark Brown 		wm831x->locked = 0;
163d2bedfe7SMark Brown 		mutex_unlock(&wm831x->io_lock);
164d2bedfe7SMark Brown 	}
165d2bedfe7SMark Brown 
166d2bedfe7SMark Brown 	return ret;
167d2bedfe7SMark Brown }
168d2bedfe7SMark Brown EXPORT_SYMBOL_GPL(wm831x_reg_unlock);
169d2bedfe7SMark Brown 
170d2bedfe7SMark Brown static int wm831x_read(struct wm831x *wm831x, unsigned short reg,
171d2bedfe7SMark Brown 		       int bytes, void *dest)
172d2bedfe7SMark Brown {
173d2bedfe7SMark Brown 	int ret, i;
174d2bedfe7SMark Brown 	u16 *buf = dest;
175d2bedfe7SMark Brown 
176d2bedfe7SMark Brown 	BUG_ON(bytes % 2);
177d2bedfe7SMark Brown 	BUG_ON(bytes <= 0);
178d2bedfe7SMark Brown 
179d2bedfe7SMark Brown 	ret = wm831x->read_dev(wm831x, reg, bytes, dest);
180d2bedfe7SMark Brown 	if (ret < 0)
181d2bedfe7SMark Brown 		return ret;
182d2bedfe7SMark Brown 
183d2bedfe7SMark Brown 	for (i = 0; i < bytes / 2; i++) {
184d2bedfe7SMark Brown 		buf[i] = be16_to_cpu(buf[i]);
185d2bedfe7SMark Brown 
186d2bedfe7SMark Brown 		dev_vdbg(wm831x->dev, "Read %04x from R%d(0x%x)\n",
187d2bedfe7SMark Brown 			 buf[i], reg + i, reg + i);
188d2bedfe7SMark Brown 	}
189d2bedfe7SMark Brown 
190d2bedfe7SMark Brown 	return 0;
191d2bedfe7SMark Brown }
192d2bedfe7SMark Brown 
193d2bedfe7SMark Brown /**
194d2bedfe7SMark Brown  * wm831x_reg_read: Read a single WM831x register.
195d2bedfe7SMark Brown  *
196d2bedfe7SMark Brown  * @wm831x: Device to read from.
197d2bedfe7SMark Brown  * @reg: Register to read.
198d2bedfe7SMark Brown  */
199d2bedfe7SMark Brown int wm831x_reg_read(struct wm831x *wm831x, unsigned short reg)
200d2bedfe7SMark Brown {
201d2bedfe7SMark Brown 	unsigned short val;
202d2bedfe7SMark Brown 	int ret;
203d2bedfe7SMark Brown 
204d2bedfe7SMark Brown 	mutex_lock(&wm831x->io_lock);
205d2bedfe7SMark Brown 
206d2bedfe7SMark Brown 	ret = wm831x_read(wm831x, reg, 2, &val);
207d2bedfe7SMark Brown 
208d2bedfe7SMark Brown 	mutex_unlock(&wm831x->io_lock);
209d2bedfe7SMark Brown 
210d2bedfe7SMark Brown 	if (ret < 0)
211d2bedfe7SMark Brown 		return ret;
212d2bedfe7SMark Brown 	else
213d2bedfe7SMark Brown 		return val;
214d2bedfe7SMark Brown }
215d2bedfe7SMark Brown EXPORT_SYMBOL_GPL(wm831x_reg_read);
216d2bedfe7SMark Brown 
217d2bedfe7SMark Brown /**
218d2bedfe7SMark Brown  * wm831x_bulk_read: Read multiple WM831x registers
219d2bedfe7SMark Brown  *
220d2bedfe7SMark Brown  * @wm831x: Device to read from
221d2bedfe7SMark Brown  * @reg: First register
222d2bedfe7SMark Brown  * @count: Number of registers
223d2bedfe7SMark Brown  * @buf: Buffer to fill.
224d2bedfe7SMark Brown  */
225d2bedfe7SMark Brown int wm831x_bulk_read(struct wm831x *wm831x, unsigned short reg,
226d2bedfe7SMark Brown 		     int count, u16 *buf)
227d2bedfe7SMark Brown {
228d2bedfe7SMark Brown 	int ret;
229d2bedfe7SMark Brown 
230d2bedfe7SMark Brown 	mutex_lock(&wm831x->io_lock);
231d2bedfe7SMark Brown 
232d2bedfe7SMark Brown 	ret = wm831x_read(wm831x, reg, count * 2, buf);
233d2bedfe7SMark Brown 
234d2bedfe7SMark Brown 	mutex_unlock(&wm831x->io_lock);
235d2bedfe7SMark Brown 
236d2bedfe7SMark Brown 	return ret;
237d2bedfe7SMark Brown }
238d2bedfe7SMark Brown EXPORT_SYMBOL_GPL(wm831x_bulk_read);
239d2bedfe7SMark Brown 
240d2bedfe7SMark Brown static int wm831x_write(struct wm831x *wm831x, unsigned short reg,
241d2bedfe7SMark Brown 			int bytes, void *src)
242d2bedfe7SMark Brown {
243d2bedfe7SMark Brown 	u16 *buf = src;
244d2bedfe7SMark Brown 	int i;
245d2bedfe7SMark Brown 
246d2bedfe7SMark Brown 	BUG_ON(bytes % 2);
247d2bedfe7SMark Brown 	BUG_ON(bytes <= 0);
248d2bedfe7SMark Brown 
249d2bedfe7SMark Brown 	for (i = 0; i < bytes / 2; i++) {
250d2bedfe7SMark Brown 		if (wm831x_reg_locked(wm831x, reg))
251d2bedfe7SMark Brown 			return -EPERM;
252d2bedfe7SMark Brown 
253d2bedfe7SMark Brown 		dev_vdbg(wm831x->dev, "Write %04x to R%d(0x%x)\n",
254d2bedfe7SMark Brown 			 buf[i], reg + i, reg + i);
255d2bedfe7SMark Brown 
256d2bedfe7SMark Brown 		buf[i] = cpu_to_be16(buf[i]);
257d2bedfe7SMark Brown 	}
258d2bedfe7SMark Brown 
259d2bedfe7SMark Brown 	return wm831x->write_dev(wm831x, reg, bytes, src);
260d2bedfe7SMark Brown }
261d2bedfe7SMark Brown 
262d2bedfe7SMark Brown /**
263d2bedfe7SMark Brown  * wm831x_reg_write: Write a single WM831x register.
264d2bedfe7SMark Brown  *
265d2bedfe7SMark Brown  * @wm831x: Device to write to.
266d2bedfe7SMark Brown  * @reg: Register to write to.
267d2bedfe7SMark Brown  * @val: Value to write.
268d2bedfe7SMark Brown  */
269d2bedfe7SMark Brown int wm831x_reg_write(struct wm831x *wm831x, unsigned short reg,
270d2bedfe7SMark Brown 		     unsigned short val)
271d2bedfe7SMark Brown {
272d2bedfe7SMark Brown 	int ret;
273d2bedfe7SMark Brown 
274d2bedfe7SMark Brown 	mutex_lock(&wm831x->io_lock);
275d2bedfe7SMark Brown 
276d2bedfe7SMark Brown 	ret = wm831x_write(wm831x, reg, 2, &val);
277d2bedfe7SMark Brown 
278d2bedfe7SMark Brown 	mutex_unlock(&wm831x->io_lock);
279d2bedfe7SMark Brown 
280d2bedfe7SMark Brown 	return ret;
281d2bedfe7SMark Brown }
282d2bedfe7SMark Brown EXPORT_SYMBOL_GPL(wm831x_reg_write);
283d2bedfe7SMark Brown 
284d2bedfe7SMark Brown /**
285d2bedfe7SMark Brown  * wm831x_set_bits: Set the value of a bitfield in a WM831x register
286d2bedfe7SMark Brown  *
287d2bedfe7SMark Brown  * @wm831x: Device to write to.
288d2bedfe7SMark Brown  * @reg: Register to write to.
289d2bedfe7SMark Brown  * @mask: Mask of bits to set.
290d2bedfe7SMark Brown  * @val: Value to set (unshifted)
291d2bedfe7SMark Brown  */
292d2bedfe7SMark Brown int wm831x_set_bits(struct wm831x *wm831x, unsigned short reg,
293d2bedfe7SMark Brown 		    unsigned short mask, unsigned short val)
294d2bedfe7SMark Brown {
295d2bedfe7SMark Brown 	int ret;
296d2bedfe7SMark Brown 	u16 r;
297d2bedfe7SMark Brown 
298d2bedfe7SMark Brown 	mutex_lock(&wm831x->io_lock);
299d2bedfe7SMark Brown 
300d2bedfe7SMark Brown 	ret = wm831x_read(wm831x, reg, 2, &r);
301d2bedfe7SMark Brown 	if (ret < 0)
302d2bedfe7SMark Brown 		goto out;
303d2bedfe7SMark Brown 
304d2bedfe7SMark Brown 	r &= ~mask;
305d2bedfe7SMark Brown 	r |= val;
306d2bedfe7SMark Brown 
307d2bedfe7SMark Brown 	ret = wm831x_write(wm831x, reg, 2, &r);
308d2bedfe7SMark Brown 
309d2bedfe7SMark Brown out:
310d2bedfe7SMark Brown 	mutex_unlock(&wm831x->io_lock);
311d2bedfe7SMark Brown 
312d2bedfe7SMark Brown 	return ret;
313d2bedfe7SMark Brown }
314d2bedfe7SMark Brown EXPORT_SYMBOL_GPL(wm831x_set_bits);
315d2bedfe7SMark Brown 
3167e9f9fd4SMark Brown /**
3177e9f9fd4SMark Brown  * wm831x_auxadc_read: Read a value from the WM831x AUXADC
3187e9f9fd4SMark Brown  *
3197e9f9fd4SMark Brown  * @wm831x: Device to read from.
3207e9f9fd4SMark Brown  * @input: AUXADC input to read.
3217e9f9fd4SMark Brown  */
3227e9f9fd4SMark Brown int wm831x_auxadc_read(struct wm831x *wm831x, enum wm831x_auxadc input)
3237e9f9fd4SMark Brown {
3247e9f9fd4SMark Brown 	int tries = 10;
3257e9f9fd4SMark Brown 	int ret, src;
3267e9f9fd4SMark Brown 
3277e9f9fd4SMark Brown 	mutex_lock(&wm831x->auxadc_lock);
3287e9f9fd4SMark Brown 
3297e9f9fd4SMark Brown 	ret = wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL,
3307e9f9fd4SMark Brown 			      WM831X_AUX_ENA, WM831X_AUX_ENA);
3317e9f9fd4SMark Brown 	if (ret < 0) {
3327e9f9fd4SMark Brown 		dev_err(wm831x->dev, "Failed to enable AUXADC: %d\n", ret);
3337e9f9fd4SMark Brown 		goto out;
3347e9f9fd4SMark Brown 	}
3357e9f9fd4SMark Brown 
3367e9f9fd4SMark Brown 	/* We force a single source at present */
3377e9f9fd4SMark Brown 	src = input;
3387e9f9fd4SMark Brown 	ret = wm831x_reg_write(wm831x, WM831X_AUXADC_SOURCE,
3397e9f9fd4SMark Brown 			       1 << src);
3407e9f9fd4SMark Brown 	if (ret < 0) {
3417e9f9fd4SMark Brown 		dev_err(wm831x->dev, "Failed to set AUXADC source: %d\n", ret);
3427e9f9fd4SMark Brown 		goto out;
3437e9f9fd4SMark Brown 	}
3447e9f9fd4SMark Brown 
3457e9f9fd4SMark Brown 	ret = wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL,
3467e9f9fd4SMark Brown 			      WM831X_AUX_CVT_ENA, WM831X_AUX_CVT_ENA);
3477e9f9fd4SMark Brown 	if (ret < 0) {
3487e9f9fd4SMark Brown 		dev_err(wm831x->dev, "Failed to start AUXADC: %d\n", ret);
3497e9f9fd4SMark Brown 		goto disable;
3507e9f9fd4SMark Brown 	}
3517e9f9fd4SMark Brown 
3527e9f9fd4SMark Brown 	do {
3537e9f9fd4SMark Brown 		msleep(1);
3547e9f9fd4SMark Brown 
3557e9f9fd4SMark Brown 		ret = wm831x_reg_read(wm831x, WM831X_AUXADC_CONTROL);
3567e9f9fd4SMark Brown 		if (ret < 0)
3577e9f9fd4SMark Brown 			ret = WM831X_AUX_CVT_ENA;
3587e9f9fd4SMark Brown 	} while ((ret & WM831X_AUX_CVT_ENA) && --tries);
3597e9f9fd4SMark Brown 
3607e9f9fd4SMark Brown 	if (ret & WM831X_AUX_CVT_ENA) {
3617e9f9fd4SMark Brown 		dev_err(wm831x->dev, "Timed out reading AUXADC\n");
3627e9f9fd4SMark Brown 		ret = -EBUSY;
3637e9f9fd4SMark Brown 		goto disable;
3647e9f9fd4SMark Brown 	}
3657e9f9fd4SMark Brown 
3667e9f9fd4SMark Brown 	ret = wm831x_reg_read(wm831x, WM831X_AUXADC_DATA);
3677e9f9fd4SMark Brown 	if (ret < 0) {
3687e9f9fd4SMark Brown 		dev_err(wm831x->dev, "Failed to read AUXADC data: %d\n", ret);
3697e9f9fd4SMark Brown 	} else {
3707e9f9fd4SMark Brown 		src = ((ret & WM831X_AUX_DATA_SRC_MASK)
3717e9f9fd4SMark Brown 		       >> WM831X_AUX_DATA_SRC_SHIFT) - 1;
3727e9f9fd4SMark Brown 
3737e9f9fd4SMark Brown 		if (src == 14)
3747e9f9fd4SMark Brown 			src = WM831X_AUX_CAL;
3757e9f9fd4SMark Brown 
3767e9f9fd4SMark Brown 		if (src != input) {
3777e9f9fd4SMark Brown 			dev_err(wm831x->dev, "Data from source %d not %d\n",
3787e9f9fd4SMark Brown 				src, input);
3797e9f9fd4SMark Brown 			ret = -EINVAL;
3807e9f9fd4SMark Brown 		} else {
3817e9f9fd4SMark Brown 			ret &= WM831X_AUX_DATA_MASK;
3827e9f9fd4SMark Brown 		}
3837e9f9fd4SMark Brown 	}
3847e9f9fd4SMark Brown 
3857e9f9fd4SMark Brown disable:
3867e9f9fd4SMark Brown 	wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL, WM831X_AUX_ENA, 0);
3877e9f9fd4SMark Brown out:
3887e9f9fd4SMark Brown 	mutex_unlock(&wm831x->auxadc_lock);
3897e9f9fd4SMark Brown 	return ret;
3907e9f9fd4SMark Brown }
3917e9f9fd4SMark Brown EXPORT_SYMBOL_GPL(wm831x_auxadc_read);
3927e9f9fd4SMark Brown 
3937e9f9fd4SMark Brown /**
3947e9f9fd4SMark Brown  * wm831x_auxadc_read_uv: Read a voltage from the WM831x AUXADC
3957e9f9fd4SMark Brown  *
3967e9f9fd4SMark Brown  * @wm831x: Device to read from.
3977e9f9fd4SMark Brown  * @input: AUXADC input to read.
3987e9f9fd4SMark Brown  */
3997e9f9fd4SMark Brown int wm831x_auxadc_read_uv(struct wm831x *wm831x, enum wm831x_auxadc input)
4007e9f9fd4SMark Brown {
4017e9f9fd4SMark Brown 	int ret;
4027e9f9fd4SMark Brown 
4037e9f9fd4SMark Brown 	ret = wm831x_auxadc_read(wm831x, input);
4047e9f9fd4SMark Brown 	if (ret < 0)
4057e9f9fd4SMark Brown 		return ret;
4067e9f9fd4SMark Brown 
4077e9f9fd4SMark Brown 	ret *= 1465;
4087e9f9fd4SMark Brown 
4097e9f9fd4SMark Brown 	return ret;
4107e9f9fd4SMark Brown }
4117e9f9fd4SMark Brown EXPORT_SYMBOL_GPL(wm831x_auxadc_read_uv);
4127e9f9fd4SMark Brown 
413d2bedfe7SMark Brown static struct resource wm831x_dcdc1_resources[] = {
414d2bedfe7SMark Brown 	{
415d2bedfe7SMark Brown 		.start = WM831X_DC1_CONTROL_1,
416d2bedfe7SMark Brown 		.end   = WM831X_DC1_DVS_CONTROL,
417d2bedfe7SMark Brown 		.flags = IORESOURCE_IO,
418d2bedfe7SMark Brown 	},
419d2bedfe7SMark Brown 	{
420d2bedfe7SMark Brown 		.name  = "UV",
421d2bedfe7SMark Brown 		.start = WM831X_IRQ_UV_DC1,
422d2bedfe7SMark Brown 		.end   = WM831X_IRQ_UV_DC1,
423d2bedfe7SMark Brown 		.flags = IORESOURCE_IRQ,
424d2bedfe7SMark Brown 	},
425d2bedfe7SMark Brown 	{
426d2bedfe7SMark Brown 		.name  = "HC",
427d2bedfe7SMark Brown 		.start = WM831X_IRQ_HC_DC1,
428d2bedfe7SMark Brown 		.end   = WM831X_IRQ_HC_DC1,
429d2bedfe7SMark Brown 		.flags = IORESOURCE_IRQ,
430d2bedfe7SMark Brown 	},
431d2bedfe7SMark Brown };
432d2bedfe7SMark Brown 
433d2bedfe7SMark Brown 
434d2bedfe7SMark Brown static struct resource wm831x_dcdc2_resources[] = {
435d2bedfe7SMark Brown 	{
436d2bedfe7SMark Brown 		.start = WM831X_DC2_CONTROL_1,
437d2bedfe7SMark Brown 		.end   = WM831X_DC2_DVS_CONTROL,
438d2bedfe7SMark Brown 		.flags = IORESOURCE_IO,
439d2bedfe7SMark Brown 	},
440d2bedfe7SMark Brown 	{
441d2bedfe7SMark Brown 		.name  = "UV",
442d2bedfe7SMark Brown 		.start = WM831X_IRQ_UV_DC2,
443d2bedfe7SMark Brown 		.end   = WM831X_IRQ_UV_DC2,
444d2bedfe7SMark Brown 		.flags = IORESOURCE_IRQ,
445d2bedfe7SMark Brown 	},
446d2bedfe7SMark Brown 	{
447d2bedfe7SMark Brown 		.name  = "HC",
448d2bedfe7SMark Brown 		.start = WM831X_IRQ_HC_DC2,
449d2bedfe7SMark Brown 		.end   = WM831X_IRQ_HC_DC2,
450d2bedfe7SMark Brown 		.flags = IORESOURCE_IRQ,
451d2bedfe7SMark Brown 	},
452d2bedfe7SMark Brown };
453d2bedfe7SMark Brown 
454d2bedfe7SMark Brown static struct resource wm831x_dcdc3_resources[] = {
455d2bedfe7SMark Brown 	{
456d2bedfe7SMark Brown 		.start = WM831X_DC3_CONTROL_1,
457d2bedfe7SMark Brown 		.end   = WM831X_DC3_SLEEP_CONTROL,
458d2bedfe7SMark Brown 		.flags = IORESOURCE_IO,
459d2bedfe7SMark Brown 	},
460d2bedfe7SMark Brown 	{
461d2bedfe7SMark Brown 		.name  = "UV",
462d2bedfe7SMark Brown 		.start = WM831X_IRQ_UV_DC3,
463d2bedfe7SMark Brown 		.end   = WM831X_IRQ_UV_DC3,
464d2bedfe7SMark Brown 		.flags = IORESOURCE_IRQ,
465d2bedfe7SMark Brown 	},
466d2bedfe7SMark Brown };
467d2bedfe7SMark Brown 
468d2bedfe7SMark Brown static struct resource wm831x_dcdc4_resources[] = {
469d2bedfe7SMark Brown 	{
470d2bedfe7SMark Brown 		.start = WM831X_DC4_CONTROL,
471d2bedfe7SMark Brown 		.end   = WM831X_DC4_SLEEP_CONTROL,
472d2bedfe7SMark Brown 		.flags = IORESOURCE_IO,
473d2bedfe7SMark Brown 	},
474d2bedfe7SMark Brown 	{
475d2bedfe7SMark Brown 		.name  = "UV",
476d2bedfe7SMark Brown 		.start = WM831X_IRQ_UV_DC4,
477d2bedfe7SMark Brown 		.end   = WM831X_IRQ_UV_DC4,
478d2bedfe7SMark Brown 		.flags = IORESOURCE_IRQ,
479d2bedfe7SMark Brown 	},
480d2bedfe7SMark Brown };
481d2bedfe7SMark Brown 
482d4e0a89eSMark Brown static struct resource wm8320_dcdc4_buck_resources[] = {
483d4e0a89eSMark Brown 	{
484d4e0a89eSMark Brown 		.start = WM831X_DC4_CONTROL,
485d4e0a89eSMark Brown 		.end   = WM832X_DC4_SLEEP_CONTROL,
486d4e0a89eSMark Brown 		.flags = IORESOURCE_IO,
487d4e0a89eSMark Brown 	},
488d4e0a89eSMark Brown 	{
489d4e0a89eSMark Brown 		.name  = "UV",
490d4e0a89eSMark Brown 		.start = WM831X_IRQ_UV_DC4,
491d4e0a89eSMark Brown 		.end   = WM831X_IRQ_UV_DC4,
492d4e0a89eSMark Brown 		.flags = IORESOURCE_IRQ,
493d4e0a89eSMark Brown 	},
494d4e0a89eSMark Brown };
495d4e0a89eSMark Brown 
496d2bedfe7SMark Brown static struct resource wm831x_gpio_resources[] = {
497d2bedfe7SMark Brown 	{
498d2bedfe7SMark Brown 		.start = WM831X_IRQ_GPIO_1,
499d2bedfe7SMark Brown 		.end   = WM831X_IRQ_GPIO_16,
500d2bedfe7SMark Brown 		.flags = IORESOURCE_IRQ,
501d2bedfe7SMark Brown 	},
502d2bedfe7SMark Brown };
503d2bedfe7SMark Brown 
504d2bedfe7SMark Brown static struct resource wm831x_isink1_resources[] = {
505d2bedfe7SMark Brown 	{
506d2bedfe7SMark Brown 		.start = WM831X_CURRENT_SINK_1,
507d2bedfe7SMark Brown 		.end   = WM831X_CURRENT_SINK_1,
508d2bedfe7SMark Brown 		.flags = IORESOURCE_IO,
509d2bedfe7SMark Brown 	},
510d2bedfe7SMark Brown 	{
511d2bedfe7SMark Brown 		.start = WM831X_IRQ_CS1,
512d2bedfe7SMark Brown 		.end   = WM831X_IRQ_CS1,
513d2bedfe7SMark Brown 		.flags = IORESOURCE_IRQ,
514d2bedfe7SMark Brown 	},
515d2bedfe7SMark Brown };
516d2bedfe7SMark Brown 
517d2bedfe7SMark Brown static struct resource wm831x_isink2_resources[] = {
518d2bedfe7SMark Brown 	{
519d2bedfe7SMark Brown 		.start = WM831X_CURRENT_SINK_2,
520d2bedfe7SMark Brown 		.end   = WM831X_CURRENT_SINK_2,
521d2bedfe7SMark Brown 		.flags = IORESOURCE_IO,
522d2bedfe7SMark Brown 	},
523d2bedfe7SMark Brown 	{
524d2bedfe7SMark Brown 		.start = WM831X_IRQ_CS2,
525d2bedfe7SMark Brown 		.end   = WM831X_IRQ_CS2,
526d2bedfe7SMark Brown 		.flags = IORESOURCE_IRQ,
527d2bedfe7SMark Brown 	},
528d2bedfe7SMark Brown };
529d2bedfe7SMark Brown 
530d2bedfe7SMark Brown static struct resource wm831x_ldo1_resources[] = {
531d2bedfe7SMark Brown 	{
532d2bedfe7SMark Brown 		.start = WM831X_LDO1_CONTROL,
533d2bedfe7SMark Brown 		.end   = WM831X_LDO1_SLEEP_CONTROL,
534d2bedfe7SMark Brown 		.flags = IORESOURCE_IO,
535d2bedfe7SMark Brown 	},
536d2bedfe7SMark Brown 	{
537d2bedfe7SMark Brown 		.name  = "UV",
538d2bedfe7SMark Brown 		.start = WM831X_IRQ_UV_LDO1,
539d2bedfe7SMark Brown 		.end   = WM831X_IRQ_UV_LDO1,
540d2bedfe7SMark Brown 		.flags = IORESOURCE_IRQ,
541d2bedfe7SMark Brown 	},
542d2bedfe7SMark Brown };
543d2bedfe7SMark Brown 
544d2bedfe7SMark Brown static struct resource wm831x_ldo2_resources[] = {
545d2bedfe7SMark Brown 	{
546d2bedfe7SMark Brown 		.start = WM831X_LDO2_CONTROL,
547d2bedfe7SMark Brown 		.end   = WM831X_LDO2_SLEEP_CONTROL,
548d2bedfe7SMark Brown 		.flags = IORESOURCE_IO,
549d2bedfe7SMark Brown 	},
550d2bedfe7SMark Brown 	{
551d2bedfe7SMark Brown 		.name  = "UV",
552d2bedfe7SMark Brown 		.start = WM831X_IRQ_UV_LDO2,
553d2bedfe7SMark Brown 		.end   = WM831X_IRQ_UV_LDO2,
554d2bedfe7SMark Brown 		.flags = IORESOURCE_IRQ,
555d2bedfe7SMark Brown 	},
556d2bedfe7SMark Brown };
557d2bedfe7SMark Brown 
558d2bedfe7SMark Brown static struct resource wm831x_ldo3_resources[] = {
559d2bedfe7SMark Brown 	{
560d2bedfe7SMark Brown 		.start = WM831X_LDO3_CONTROL,
561d2bedfe7SMark Brown 		.end   = WM831X_LDO3_SLEEP_CONTROL,
562d2bedfe7SMark Brown 		.flags = IORESOURCE_IO,
563d2bedfe7SMark Brown 	},
564d2bedfe7SMark Brown 	{
565d2bedfe7SMark Brown 		.name  = "UV",
566d2bedfe7SMark Brown 		.start = WM831X_IRQ_UV_LDO3,
567d2bedfe7SMark Brown 		.end   = WM831X_IRQ_UV_LDO3,
568d2bedfe7SMark Brown 		.flags = IORESOURCE_IRQ,
569d2bedfe7SMark Brown 	},
570d2bedfe7SMark Brown };
571d2bedfe7SMark Brown 
572d2bedfe7SMark Brown static struct resource wm831x_ldo4_resources[] = {
573d2bedfe7SMark Brown 	{
574d2bedfe7SMark Brown 		.start = WM831X_LDO4_CONTROL,
575d2bedfe7SMark Brown 		.end   = WM831X_LDO4_SLEEP_CONTROL,
576d2bedfe7SMark Brown 		.flags = IORESOURCE_IO,
577d2bedfe7SMark Brown 	},
578d2bedfe7SMark Brown 	{
579d2bedfe7SMark Brown 		.name  = "UV",
580d2bedfe7SMark Brown 		.start = WM831X_IRQ_UV_LDO4,
581d2bedfe7SMark Brown 		.end   = WM831X_IRQ_UV_LDO4,
582d2bedfe7SMark Brown 		.flags = IORESOURCE_IRQ,
583d2bedfe7SMark Brown 	},
584d2bedfe7SMark Brown };
585d2bedfe7SMark Brown 
586d2bedfe7SMark Brown static struct resource wm831x_ldo5_resources[] = {
587d2bedfe7SMark Brown 	{
588d2bedfe7SMark Brown 		.start = WM831X_LDO5_CONTROL,
589d2bedfe7SMark Brown 		.end   = WM831X_LDO5_SLEEP_CONTROL,
590d2bedfe7SMark Brown 		.flags = IORESOURCE_IO,
591d2bedfe7SMark Brown 	},
592d2bedfe7SMark Brown 	{
593d2bedfe7SMark Brown 		.name  = "UV",
594d2bedfe7SMark Brown 		.start = WM831X_IRQ_UV_LDO5,
595d2bedfe7SMark Brown 		.end   = WM831X_IRQ_UV_LDO5,
596d2bedfe7SMark Brown 		.flags = IORESOURCE_IRQ,
597d2bedfe7SMark Brown 	},
598d2bedfe7SMark Brown };
599d2bedfe7SMark Brown 
600d2bedfe7SMark Brown static struct resource wm831x_ldo6_resources[] = {
601d2bedfe7SMark Brown 	{
602d2bedfe7SMark Brown 		.start = WM831X_LDO6_CONTROL,
603d2bedfe7SMark Brown 		.end   = WM831X_LDO6_SLEEP_CONTROL,
604d2bedfe7SMark Brown 		.flags = IORESOURCE_IO,
605d2bedfe7SMark Brown 	},
606d2bedfe7SMark Brown 	{
607d2bedfe7SMark Brown 		.name  = "UV",
608d2bedfe7SMark Brown 		.start = WM831X_IRQ_UV_LDO6,
609d2bedfe7SMark Brown 		.end   = WM831X_IRQ_UV_LDO6,
610d2bedfe7SMark Brown 		.flags = IORESOURCE_IRQ,
611d2bedfe7SMark Brown 	},
612d2bedfe7SMark Brown };
613d2bedfe7SMark Brown 
614d2bedfe7SMark Brown static struct resource wm831x_ldo7_resources[] = {
615d2bedfe7SMark Brown 	{
616d2bedfe7SMark Brown 		.start = WM831X_LDO7_CONTROL,
617d2bedfe7SMark Brown 		.end   = WM831X_LDO7_SLEEP_CONTROL,
618d2bedfe7SMark Brown 		.flags = IORESOURCE_IO,
619d2bedfe7SMark Brown 	},
620d2bedfe7SMark Brown 	{
621d2bedfe7SMark Brown 		.name  = "UV",
622d2bedfe7SMark Brown 		.start = WM831X_IRQ_UV_LDO7,
623d2bedfe7SMark Brown 		.end   = WM831X_IRQ_UV_LDO7,
624d2bedfe7SMark Brown 		.flags = IORESOURCE_IRQ,
625d2bedfe7SMark Brown 	},
626d2bedfe7SMark Brown };
627d2bedfe7SMark Brown 
628d2bedfe7SMark Brown static struct resource wm831x_ldo8_resources[] = {
629d2bedfe7SMark Brown 	{
630d2bedfe7SMark Brown 		.start = WM831X_LDO8_CONTROL,
631d2bedfe7SMark Brown 		.end   = WM831X_LDO8_SLEEP_CONTROL,
632d2bedfe7SMark Brown 		.flags = IORESOURCE_IO,
633d2bedfe7SMark Brown 	},
634d2bedfe7SMark Brown 	{
635d2bedfe7SMark Brown 		.name  = "UV",
636d2bedfe7SMark Brown 		.start = WM831X_IRQ_UV_LDO8,
637d2bedfe7SMark Brown 		.end   = WM831X_IRQ_UV_LDO8,
638d2bedfe7SMark Brown 		.flags = IORESOURCE_IRQ,
639d2bedfe7SMark Brown 	},
640d2bedfe7SMark Brown };
641d2bedfe7SMark Brown 
642d2bedfe7SMark Brown static struct resource wm831x_ldo9_resources[] = {
643d2bedfe7SMark Brown 	{
644d2bedfe7SMark Brown 		.start = WM831X_LDO9_CONTROL,
645d2bedfe7SMark Brown 		.end   = WM831X_LDO9_SLEEP_CONTROL,
646d2bedfe7SMark Brown 		.flags = IORESOURCE_IO,
647d2bedfe7SMark Brown 	},
648d2bedfe7SMark Brown 	{
649d2bedfe7SMark Brown 		.name  = "UV",
650d2bedfe7SMark Brown 		.start = WM831X_IRQ_UV_LDO9,
651d2bedfe7SMark Brown 		.end   = WM831X_IRQ_UV_LDO9,
652d2bedfe7SMark Brown 		.flags = IORESOURCE_IRQ,
653d2bedfe7SMark Brown 	},
654d2bedfe7SMark Brown };
655d2bedfe7SMark Brown 
656d2bedfe7SMark Brown static struct resource wm831x_ldo10_resources[] = {
657d2bedfe7SMark Brown 	{
658d2bedfe7SMark Brown 		.start = WM831X_LDO10_CONTROL,
659d2bedfe7SMark Brown 		.end   = WM831X_LDO10_SLEEP_CONTROL,
660d2bedfe7SMark Brown 		.flags = IORESOURCE_IO,
661d2bedfe7SMark Brown 	},
662d2bedfe7SMark Brown 	{
663d2bedfe7SMark Brown 		.name  = "UV",
664d2bedfe7SMark Brown 		.start = WM831X_IRQ_UV_LDO10,
665d2bedfe7SMark Brown 		.end   = WM831X_IRQ_UV_LDO10,
666d2bedfe7SMark Brown 		.flags = IORESOURCE_IRQ,
667d2bedfe7SMark Brown 	},
668d2bedfe7SMark Brown };
669d2bedfe7SMark Brown 
670d2bedfe7SMark Brown static struct resource wm831x_ldo11_resources[] = {
671d2bedfe7SMark Brown 	{
672d2bedfe7SMark Brown 		.start = WM831X_LDO11_ON_CONTROL,
673d2bedfe7SMark Brown 		.end   = WM831X_LDO11_SLEEP_CONTROL,
674d2bedfe7SMark Brown 		.flags = IORESOURCE_IO,
675d2bedfe7SMark Brown 	},
676d2bedfe7SMark Brown };
677d2bedfe7SMark Brown 
678d2bedfe7SMark Brown static struct resource wm831x_on_resources[] = {
679d2bedfe7SMark Brown 	{
680d2bedfe7SMark Brown 		.start = WM831X_IRQ_ON,
681d2bedfe7SMark Brown 		.end   = WM831X_IRQ_ON,
682d2bedfe7SMark Brown 		.flags = IORESOURCE_IRQ,
683d2bedfe7SMark Brown 	},
684d2bedfe7SMark Brown };
685d2bedfe7SMark Brown 
686d2bedfe7SMark Brown 
687d2bedfe7SMark Brown static struct resource wm831x_power_resources[] = {
688d2bedfe7SMark Brown 	{
689d2bedfe7SMark Brown 		.name = "SYSLO",
690d2bedfe7SMark Brown 		.start = WM831X_IRQ_PPM_SYSLO,
691d2bedfe7SMark Brown 		.end   = WM831X_IRQ_PPM_SYSLO,
692d2bedfe7SMark Brown 		.flags = IORESOURCE_IRQ,
693d2bedfe7SMark Brown 	},
694d2bedfe7SMark Brown 	{
695d2bedfe7SMark Brown 		.name = "PWR SRC",
696d2bedfe7SMark Brown 		.start = WM831X_IRQ_PPM_PWR_SRC,
697d2bedfe7SMark Brown 		.end   = WM831X_IRQ_PPM_PWR_SRC,
698d2bedfe7SMark Brown 		.flags = IORESOURCE_IRQ,
699d2bedfe7SMark Brown 	},
700d2bedfe7SMark Brown 	{
701d2bedfe7SMark Brown 		.name = "USB CURR",
702d2bedfe7SMark Brown 		.start = WM831X_IRQ_PPM_USB_CURR,
703d2bedfe7SMark Brown 		.end   = WM831X_IRQ_PPM_USB_CURR,
704d2bedfe7SMark Brown 		.flags = IORESOURCE_IRQ,
705d2bedfe7SMark Brown 	},
706d2bedfe7SMark Brown 	{
707d2bedfe7SMark Brown 		.name = "BATT HOT",
708d2bedfe7SMark Brown 		.start = WM831X_IRQ_CHG_BATT_HOT,
709d2bedfe7SMark Brown 		.end   = WM831X_IRQ_CHG_BATT_HOT,
710d2bedfe7SMark Brown 		.flags = IORESOURCE_IRQ,
711d2bedfe7SMark Brown 	},
712d2bedfe7SMark Brown 	{
713d2bedfe7SMark Brown 		.name = "BATT COLD",
714d2bedfe7SMark Brown 		.start = WM831X_IRQ_CHG_BATT_COLD,
715d2bedfe7SMark Brown 		.end   = WM831X_IRQ_CHG_BATT_COLD,
716d2bedfe7SMark Brown 		.flags = IORESOURCE_IRQ,
717d2bedfe7SMark Brown 	},
718d2bedfe7SMark Brown 	{
719d2bedfe7SMark Brown 		.name = "BATT FAIL",
720d2bedfe7SMark Brown 		.start = WM831X_IRQ_CHG_BATT_FAIL,
721d2bedfe7SMark Brown 		.end   = WM831X_IRQ_CHG_BATT_FAIL,
722d2bedfe7SMark Brown 		.flags = IORESOURCE_IRQ,
723d2bedfe7SMark Brown 	},
724d2bedfe7SMark Brown 	{
725d2bedfe7SMark Brown 		.name = "OV",
726d2bedfe7SMark Brown 		.start = WM831X_IRQ_CHG_OV,
727d2bedfe7SMark Brown 		.end   = WM831X_IRQ_CHG_OV,
728d2bedfe7SMark Brown 		.flags = IORESOURCE_IRQ,
729d2bedfe7SMark Brown 	},
730d2bedfe7SMark Brown 	{
731d2bedfe7SMark Brown 		.name = "END",
732d2bedfe7SMark Brown 		.start = WM831X_IRQ_CHG_END,
733d2bedfe7SMark Brown 		.end   = WM831X_IRQ_CHG_END,
734d2bedfe7SMark Brown 		.flags = IORESOURCE_IRQ,
735d2bedfe7SMark Brown 	},
736d2bedfe7SMark Brown 	{
737d2bedfe7SMark Brown 		.name = "TO",
738d2bedfe7SMark Brown 		.start = WM831X_IRQ_CHG_TO,
739d2bedfe7SMark Brown 		.end   = WM831X_IRQ_CHG_TO,
740d2bedfe7SMark Brown 		.flags = IORESOURCE_IRQ,
741d2bedfe7SMark Brown 	},
742d2bedfe7SMark Brown 	{
743d2bedfe7SMark Brown 		.name = "MODE",
744d2bedfe7SMark Brown 		.start = WM831X_IRQ_CHG_MODE,
745d2bedfe7SMark Brown 		.end   = WM831X_IRQ_CHG_MODE,
746d2bedfe7SMark Brown 		.flags = IORESOURCE_IRQ,
747d2bedfe7SMark Brown 	},
748d2bedfe7SMark Brown 	{
749d2bedfe7SMark Brown 		.name = "START",
750d2bedfe7SMark Brown 		.start = WM831X_IRQ_CHG_START,
751d2bedfe7SMark Brown 		.end   = WM831X_IRQ_CHG_START,
752d2bedfe7SMark Brown 		.flags = IORESOURCE_IRQ,
753d2bedfe7SMark Brown 	},
754d2bedfe7SMark Brown };
755d2bedfe7SMark Brown 
756d2bedfe7SMark Brown static struct resource wm831x_rtc_resources[] = {
757d2bedfe7SMark Brown 	{
758d2bedfe7SMark Brown 		.name = "PER",
759d2bedfe7SMark Brown 		.start = WM831X_IRQ_RTC_PER,
760d2bedfe7SMark Brown 		.end   = WM831X_IRQ_RTC_PER,
761d2bedfe7SMark Brown 		.flags = IORESOURCE_IRQ,
762d2bedfe7SMark Brown 	},
763d2bedfe7SMark Brown 	{
764d2bedfe7SMark Brown 		.name = "ALM",
765d2bedfe7SMark Brown 		.start = WM831X_IRQ_RTC_ALM,
766d2bedfe7SMark Brown 		.end   = WM831X_IRQ_RTC_ALM,
767d2bedfe7SMark Brown 		.flags = IORESOURCE_IRQ,
768d2bedfe7SMark Brown 	},
769d2bedfe7SMark Brown };
770d2bedfe7SMark Brown 
771d2bedfe7SMark Brown static struct resource wm831x_status1_resources[] = {
772d2bedfe7SMark Brown 	{
773d2bedfe7SMark Brown 		.start = WM831X_STATUS_LED_1,
774d2bedfe7SMark Brown 		.end   = WM831X_STATUS_LED_1,
775d2bedfe7SMark Brown 		.flags = IORESOURCE_IO,
776d2bedfe7SMark Brown 	},
777d2bedfe7SMark Brown };
778d2bedfe7SMark Brown 
779d2bedfe7SMark Brown static struct resource wm831x_status2_resources[] = {
780d2bedfe7SMark Brown 	{
781d2bedfe7SMark Brown 		.start = WM831X_STATUS_LED_2,
782d2bedfe7SMark Brown 		.end   = WM831X_STATUS_LED_2,
783d2bedfe7SMark Brown 		.flags = IORESOURCE_IO,
784d2bedfe7SMark Brown 	},
785d2bedfe7SMark Brown };
786d2bedfe7SMark Brown 
787d2bedfe7SMark Brown static struct resource wm831x_touch_resources[] = {
788d2bedfe7SMark Brown 	{
789d2bedfe7SMark Brown 		.name = "TCHPD",
790d2bedfe7SMark Brown 		.start = WM831X_IRQ_TCHPD,
791d2bedfe7SMark Brown 		.end   = WM831X_IRQ_TCHPD,
792d2bedfe7SMark Brown 		.flags = IORESOURCE_IRQ,
793d2bedfe7SMark Brown 	},
794d2bedfe7SMark Brown 	{
795d2bedfe7SMark Brown 		.name = "TCHDATA",
796d2bedfe7SMark Brown 		.start = WM831X_IRQ_TCHDATA,
797d2bedfe7SMark Brown 		.end   = WM831X_IRQ_TCHDATA,
798d2bedfe7SMark Brown 		.flags = IORESOURCE_IRQ,
799d2bedfe7SMark Brown 	},
800d2bedfe7SMark Brown };
801d2bedfe7SMark Brown 
802d2bedfe7SMark Brown static struct resource wm831x_wdt_resources[] = {
803d2bedfe7SMark Brown 	{
804d2bedfe7SMark Brown 		.start = WM831X_IRQ_WDOG_TO,
805d2bedfe7SMark Brown 		.end   = WM831X_IRQ_WDOG_TO,
806d2bedfe7SMark Brown 		.flags = IORESOURCE_IRQ,
807d2bedfe7SMark Brown 	},
808d2bedfe7SMark Brown };
809d2bedfe7SMark Brown 
810d2bedfe7SMark Brown static struct mfd_cell wm8310_devs[] = {
811d2bedfe7SMark Brown 	{
812c26964eaSMark Brown 		.name = "wm831x-backup",
813c26964eaSMark Brown 	},
814c26964eaSMark Brown 	{
815d2bedfe7SMark Brown 		.name = "wm831x-buckv",
816d2bedfe7SMark Brown 		.id = 1,
817d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_dcdc1_resources),
818d2bedfe7SMark Brown 		.resources = wm831x_dcdc1_resources,
819d2bedfe7SMark Brown 	},
820d2bedfe7SMark Brown 	{
821d2bedfe7SMark Brown 		.name = "wm831x-buckv",
822d2bedfe7SMark Brown 		.id = 2,
823d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_dcdc2_resources),
824d2bedfe7SMark Brown 		.resources = wm831x_dcdc2_resources,
825d2bedfe7SMark Brown 	},
826d2bedfe7SMark Brown 	{
827d2bedfe7SMark Brown 		.name = "wm831x-buckp",
828d2bedfe7SMark Brown 		.id = 3,
829d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_dcdc3_resources),
830d2bedfe7SMark Brown 		.resources = wm831x_dcdc3_resources,
831d2bedfe7SMark Brown 	},
832d2bedfe7SMark Brown 	{
833d2bedfe7SMark Brown 		.name = "wm831x-boostp",
834d2bedfe7SMark Brown 		.id = 4,
835d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_dcdc4_resources),
836d2bedfe7SMark Brown 		.resources = wm831x_dcdc4_resources,
837d2bedfe7SMark Brown 	},
838d2bedfe7SMark Brown 	{
839d2bedfe7SMark Brown 		.name = "wm831x-epe",
840d2bedfe7SMark Brown 		.id = 1,
841d2bedfe7SMark Brown 	},
842d2bedfe7SMark Brown 	{
843d2bedfe7SMark Brown 		.name = "wm831x-epe",
844d2bedfe7SMark Brown 		.id = 2,
845d2bedfe7SMark Brown 	},
846d2bedfe7SMark Brown 	{
847d2bedfe7SMark Brown 		.name = "wm831x-gpio",
848d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_gpio_resources),
849d2bedfe7SMark Brown 		.resources = wm831x_gpio_resources,
850d2bedfe7SMark Brown 	},
851d2bedfe7SMark Brown 	{
852d2bedfe7SMark Brown 		.name = "wm831x-hwmon",
853d2bedfe7SMark Brown 	},
854d2bedfe7SMark Brown 	{
855d2bedfe7SMark Brown 		.name = "wm831x-isink",
856d2bedfe7SMark Brown 		.id = 1,
857d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_isink1_resources),
858d2bedfe7SMark Brown 		.resources = wm831x_isink1_resources,
859d2bedfe7SMark Brown 	},
860d2bedfe7SMark Brown 	{
861d2bedfe7SMark Brown 		.name = "wm831x-isink",
862d2bedfe7SMark Brown 		.id = 2,
863d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_isink2_resources),
864d2bedfe7SMark Brown 		.resources = wm831x_isink2_resources,
865d2bedfe7SMark Brown 	},
866d2bedfe7SMark Brown 	{
867d2bedfe7SMark Brown 		.name = "wm831x-ldo",
868d2bedfe7SMark Brown 		.id = 1,
869d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_ldo1_resources),
870d2bedfe7SMark Brown 		.resources = wm831x_ldo1_resources,
871d2bedfe7SMark Brown 	},
872d2bedfe7SMark Brown 	{
873d2bedfe7SMark Brown 		.name = "wm831x-ldo",
874d2bedfe7SMark Brown 		.id = 2,
875d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_ldo2_resources),
876d2bedfe7SMark Brown 		.resources = wm831x_ldo2_resources,
877d2bedfe7SMark Brown 	},
878d2bedfe7SMark Brown 	{
879d2bedfe7SMark Brown 		.name = "wm831x-ldo",
880d2bedfe7SMark Brown 		.id = 3,
881d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_ldo3_resources),
882d2bedfe7SMark Brown 		.resources = wm831x_ldo3_resources,
883d2bedfe7SMark Brown 	},
884d2bedfe7SMark Brown 	{
885d2bedfe7SMark Brown 		.name = "wm831x-ldo",
886d2bedfe7SMark Brown 		.id = 4,
887d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_ldo4_resources),
888d2bedfe7SMark Brown 		.resources = wm831x_ldo4_resources,
889d2bedfe7SMark Brown 	},
890d2bedfe7SMark Brown 	{
891d2bedfe7SMark Brown 		.name = "wm831x-ldo",
892d2bedfe7SMark Brown 		.id = 5,
893d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_ldo5_resources),
894d2bedfe7SMark Brown 		.resources = wm831x_ldo5_resources,
895d2bedfe7SMark Brown 	},
896d2bedfe7SMark Brown 	{
897d2bedfe7SMark Brown 		.name = "wm831x-ldo",
898d2bedfe7SMark Brown 		.id = 6,
899d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_ldo6_resources),
900d2bedfe7SMark Brown 		.resources = wm831x_ldo6_resources,
901d2bedfe7SMark Brown 	},
902d2bedfe7SMark Brown 	{
903d2bedfe7SMark Brown 		.name = "wm831x-aldo",
904d2bedfe7SMark Brown 		.id = 7,
905d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_ldo7_resources),
906d2bedfe7SMark Brown 		.resources = wm831x_ldo7_resources,
907d2bedfe7SMark Brown 	},
908d2bedfe7SMark Brown 	{
909d2bedfe7SMark Brown 		.name = "wm831x-aldo",
910d2bedfe7SMark Brown 		.id = 8,
911d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_ldo8_resources),
912d2bedfe7SMark Brown 		.resources = wm831x_ldo8_resources,
913d2bedfe7SMark Brown 	},
914d2bedfe7SMark Brown 	{
915d2bedfe7SMark Brown 		.name = "wm831x-aldo",
916d2bedfe7SMark Brown 		.id = 9,
917d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_ldo9_resources),
918d2bedfe7SMark Brown 		.resources = wm831x_ldo9_resources,
919d2bedfe7SMark Brown 	},
920d2bedfe7SMark Brown 	{
921d2bedfe7SMark Brown 		.name = "wm831x-aldo",
922d2bedfe7SMark Brown 		.id = 10,
923d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_ldo10_resources),
924d2bedfe7SMark Brown 		.resources = wm831x_ldo10_resources,
925d2bedfe7SMark Brown 	},
926d2bedfe7SMark Brown 	{
927d2bedfe7SMark Brown 		.name = "wm831x-alive-ldo",
928d2bedfe7SMark Brown 		.id = 11,
929d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_ldo11_resources),
930d2bedfe7SMark Brown 		.resources = wm831x_ldo11_resources,
931d2bedfe7SMark Brown 	},
932d2bedfe7SMark Brown 	{
933d2bedfe7SMark Brown 		.name = "wm831x-on",
934d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_on_resources),
935d2bedfe7SMark Brown 		.resources = wm831x_on_resources,
936d2bedfe7SMark Brown 	},
937d2bedfe7SMark Brown 	{
938d2bedfe7SMark Brown 		.name = "wm831x-power",
939d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_power_resources),
940d2bedfe7SMark Brown 		.resources = wm831x_power_resources,
941d2bedfe7SMark Brown 	},
942d2bedfe7SMark Brown 	{
943d2bedfe7SMark Brown 		.name = "wm831x-rtc",
944d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_rtc_resources),
945d2bedfe7SMark Brown 		.resources = wm831x_rtc_resources,
946d2bedfe7SMark Brown 	},
947d2bedfe7SMark Brown 	{
948d2bedfe7SMark Brown 		.name = "wm831x-status",
949d2bedfe7SMark Brown 		.id = 1,
950d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_status1_resources),
951d2bedfe7SMark Brown 		.resources = wm831x_status1_resources,
952d2bedfe7SMark Brown 	},
953d2bedfe7SMark Brown 	{
954d2bedfe7SMark Brown 		.name = "wm831x-status",
955d2bedfe7SMark Brown 		.id = 2,
956d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_status2_resources),
957d2bedfe7SMark Brown 		.resources = wm831x_status2_resources,
958d2bedfe7SMark Brown 	},
959d2bedfe7SMark Brown 	{
960d2bedfe7SMark Brown 		.name = "wm831x-watchdog",
961d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_wdt_resources),
962d2bedfe7SMark Brown 		.resources = wm831x_wdt_resources,
963d2bedfe7SMark Brown 	},
964d2bedfe7SMark Brown };
965d2bedfe7SMark Brown 
966d2bedfe7SMark Brown static struct mfd_cell wm8311_devs[] = {
967d2bedfe7SMark Brown 	{
968c26964eaSMark Brown 		.name = "wm831x-backup",
969c26964eaSMark Brown 	},
970c26964eaSMark Brown 	{
971d2bedfe7SMark Brown 		.name = "wm831x-buckv",
972d2bedfe7SMark Brown 		.id = 1,
973d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_dcdc1_resources),
974d2bedfe7SMark Brown 		.resources = wm831x_dcdc1_resources,
975d2bedfe7SMark Brown 	},
976d2bedfe7SMark Brown 	{
977d2bedfe7SMark Brown 		.name = "wm831x-buckv",
978d2bedfe7SMark Brown 		.id = 2,
979d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_dcdc2_resources),
980d2bedfe7SMark Brown 		.resources = wm831x_dcdc2_resources,
981d2bedfe7SMark Brown 	},
982d2bedfe7SMark Brown 	{
983d2bedfe7SMark Brown 		.name = "wm831x-buckp",
984d2bedfe7SMark Brown 		.id = 3,
985d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_dcdc3_resources),
986d2bedfe7SMark Brown 		.resources = wm831x_dcdc3_resources,
987d2bedfe7SMark Brown 	},
988d2bedfe7SMark Brown 	{
989d2bedfe7SMark Brown 		.name = "wm831x-boostp",
990d2bedfe7SMark Brown 		.id = 4,
991d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_dcdc4_resources),
992d2bedfe7SMark Brown 		.resources = wm831x_dcdc4_resources,
993d2bedfe7SMark Brown 	},
994d2bedfe7SMark Brown 	{
995d2bedfe7SMark Brown 		.name = "wm831x-epe",
996d2bedfe7SMark Brown 		.id = 1,
997d2bedfe7SMark Brown 	},
998d2bedfe7SMark Brown 	{
999d2bedfe7SMark Brown 		.name = "wm831x-epe",
1000d2bedfe7SMark Brown 		.id = 2,
1001d2bedfe7SMark Brown 	},
1002d2bedfe7SMark Brown 	{
1003d2bedfe7SMark Brown 		.name = "wm831x-gpio",
1004d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_gpio_resources),
1005d2bedfe7SMark Brown 		.resources = wm831x_gpio_resources,
1006d2bedfe7SMark Brown 	},
1007d2bedfe7SMark Brown 	{
1008d2bedfe7SMark Brown 		.name = "wm831x-hwmon",
1009d2bedfe7SMark Brown 	},
1010d2bedfe7SMark Brown 	{
1011d2bedfe7SMark Brown 		.name = "wm831x-isink",
1012d2bedfe7SMark Brown 		.id = 1,
1013d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_isink1_resources),
1014d2bedfe7SMark Brown 		.resources = wm831x_isink1_resources,
1015d2bedfe7SMark Brown 	},
1016d2bedfe7SMark Brown 	{
1017d2bedfe7SMark Brown 		.name = "wm831x-isink",
1018d2bedfe7SMark Brown 		.id = 2,
1019d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_isink2_resources),
1020d2bedfe7SMark Brown 		.resources = wm831x_isink2_resources,
1021d2bedfe7SMark Brown 	},
1022d2bedfe7SMark Brown 	{
1023d2bedfe7SMark Brown 		.name = "wm831x-ldo",
1024d2bedfe7SMark Brown 		.id = 1,
1025d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_ldo1_resources),
1026d2bedfe7SMark Brown 		.resources = wm831x_ldo1_resources,
1027d2bedfe7SMark Brown 	},
1028d2bedfe7SMark Brown 	{
1029d2bedfe7SMark Brown 		.name = "wm831x-ldo",
1030d2bedfe7SMark Brown 		.id = 2,
1031d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_ldo2_resources),
1032d2bedfe7SMark Brown 		.resources = wm831x_ldo2_resources,
1033d2bedfe7SMark Brown 	},
1034d2bedfe7SMark Brown 	{
1035d2bedfe7SMark Brown 		.name = "wm831x-ldo",
1036d2bedfe7SMark Brown 		.id = 3,
1037d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_ldo3_resources),
1038d2bedfe7SMark Brown 		.resources = wm831x_ldo3_resources,
1039d2bedfe7SMark Brown 	},
1040d2bedfe7SMark Brown 	{
1041d2bedfe7SMark Brown 		.name = "wm831x-ldo",
1042d2bedfe7SMark Brown 		.id = 4,
1043d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_ldo4_resources),
1044d2bedfe7SMark Brown 		.resources = wm831x_ldo4_resources,
1045d2bedfe7SMark Brown 	},
1046d2bedfe7SMark Brown 	{
1047d2bedfe7SMark Brown 		.name = "wm831x-ldo",
1048d2bedfe7SMark Brown 		.id = 5,
1049d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_ldo5_resources),
1050d2bedfe7SMark Brown 		.resources = wm831x_ldo5_resources,
1051d2bedfe7SMark Brown 	},
1052d2bedfe7SMark Brown 	{
1053d2bedfe7SMark Brown 		.name = "wm831x-aldo",
1054d2bedfe7SMark Brown 		.id = 7,
1055d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_ldo7_resources),
1056d2bedfe7SMark Brown 		.resources = wm831x_ldo7_resources,
1057d2bedfe7SMark Brown 	},
1058d2bedfe7SMark Brown 	{
1059d2bedfe7SMark Brown 		.name = "wm831x-alive-ldo",
1060d2bedfe7SMark Brown 		.id = 11,
1061d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_ldo11_resources),
1062d2bedfe7SMark Brown 		.resources = wm831x_ldo11_resources,
1063d2bedfe7SMark Brown 	},
1064d2bedfe7SMark Brown 	{
1065d2bedfe7SMark Brown 		.name = "wm831x-on",
1066d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_on_resources),
1067d2bedfe7SMark Brown 		.resources = wm831x_on_resources,
1068d2bedfe7SMark Brown 	},
1069d2bedfe7SMark Brown 	{
1070d2bedfe7SMark Brown 		.name = "wm831x-power",
1071d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_power_resources),
1072d2bedfe7SMark Brown 		.resources = wm831x_power_resources,
1073d2bedfe7SMark Brown 	},
1074d2bedfe7SMark Brown 	{
1075d2bedfe7SMark Brown 		.name = "wm831x-rtc",
1076d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_rtc_resources),
1077d2bedfe7SMark Brown 		.resources = wm831x_rtc_resources,
1078d2bedfe7SMark Brown 	},
1079d2bedfe7SMark Brown 	{
1080d2bedfe7SMark Brown 		.name = "wm831x-status",
1081d2bedfe7SMark Brown 		.id = 1,
1082d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_status1_resources),
1083d2bedfe7SMark Brown 		.resources = wm831x_status1_resources,
1084d2bedfe7SMark Brown 	},
1085d2bedfe7SMark Brown 	{
1086d2bedfe7SMark Brown 		.name = "wm831x-status",
1087d2bedfe7SMark Brown 		.id = 2,
1088d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_status2_resources),
1089d2bedfe7SMark Brown 		.resources = wm831x_status2_resources,
1090d2bedfe7SMark Brown 	},
1091d2bedfe7SMark Brown 	{
1092d2bedfe7SMark Brown 		.name = "wm831x-touch",
1093d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_touch_resources),
1094d2bedfe7SMark Brown 		.resources = wm831x_touch_resources,
1095d2bedfe7SMark Brown 	},
1096d2bedfe7SMark Brown 	{
1097d2bedfe7SMark Brown 		.name = "wm831x-watchdog",
1098d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_wdt_resources),
1099d2bedfe7SMark Brown 		.resources = wm831x_wdt_resources,
1100d2bedfe7SMark Brown 	},
1101d2bedfe7SMark Brown };
1102d2bedfe7SMark Brown 
1103d2bedfe7SMark Brown static struct mfd_cell wm8312_devs[] = {
1104d2bedfe7SMark Brown 	{
1105c26964eaSMark Brown 		.name = "wm831x-backup",
1106c26964eaSMark Brown 	},
1107c26964eaSMark Brown 	{
1108d2bedfe7SMark Brown 		.name = "wm831x-buckv",
1109d2bedfe7SMark Brown 		.id = 1,
1110d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_dcdc1_resources),
1111d2bedfe7SMark Brown 		.resources = wm831x_dcdc1_resources,
1112d2bedfe7SMark Brown 	},
1113d2bedfe7SMark Brown 	{
1114d2bedfe7SMark Brown 		.name = "wm831x-buckv",
1115d2bedfe7SMark Brown 		.id = 2,
1116d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_dcdc2_resources),
1117d2bedfe7SMark Brown 		.resources = wm831x_dcdc2_resources,
1118d2bedfe7SMark Brown 	},
1119d2bedfe7SMark Brown 	{
1120d2bedfe7SMark Brown 		.name = "wm831x-buckp",
1121d2bedfe7SMark Brown 		.id = 3,
1122d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_dcdc3_resources),
1123d2bedfe7SMark Brown 		.resources = wm831x_dcdc3_resources,
1124d2bedfe7SMark Brown 	},
1125d2bedfe7SMark Brown 	{
1126d2bedfe7SMark Brown 		.name = "wm831x-boostp",
1127d2bedfe7SMark Brown 		.id = 4,
1128d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_dcdc4_resources),
1129d2bedfe7SMark Brown 		.resources = wm831x_dcdc4_resources,
1130d2bedfe7SMark Brown 	},
1131d2bedfe7SMark Brown 	{
1132d2bedfe7SMark Brown 		.name = "wm831x-epe",
1133d2bedfe7SMark Brown 		.id = 1,
1134d2bedfe7SMark Brown 	},
1135d2bedfe7SMark Brown 	{
1136d2bedfe7SMark Brown 		.name = "wm831x-epe",
1137d2bedfe7SMark Brown 		.id = 2,
1138d2bedfe7SMark Brown 	},
1139d2bedfe7SMark Brown 	{
1140d2bedfe7SMark Brown 		.name = "wm831x-gpio",
1141d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_gpio_resources),
1142d2bedfe7SMark Brown 		.resources = wm831x_gpio_resources,
1143d2bedfe7SMark Brown 	},
1144d2bedfe7SMark Brown 	{
1145d2bedfe7SMark Brown 		.name = "wm831x-hwmon",
1146d2bedfe7SMark Brown 	},
1147d2bedfe7SMark Brown 	{
1148d2bedfe7SMark Brown 		.name = "wm831x-isink",
1149d2bedfe7SMark Brown 		.id = 1,
1150d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_isink1_resources),
1151d2bedfe7SMark Brown 		.resources = wm831x_isink1_resources,
1152d2bedfe7SMark Brown 	},
1153d2bedfe7SMark Brown 	{
1154d2bedfe7SMark Brown 		.name = "wm831x-isink",
1155d2bedfe7SMark Brown 		.id = 2,
1156d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_isink2_resources),
1157d2bedfe7SMark Brown 		.resources = wm831x_isink2_resources,
1158d2bedfe7SMark Brown 	},
1159d2bedfe7SMark Brown 	{
1160d2bedfe7SMark Brown 		.name = "wm831x-ldo",
1161d2bedfe7SMark Brown 		.id = 1,
1162d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_ldo1_resources),
1163d2bedfe7SMark Brown 		.resources = wm831x_ldo1_resources,
1164d2bedfe7SMark Brown 	},
1165d2bedfe7SMark Brown 	{
1166d2bedfe7SMark Brown 		.name = "wm831x-ldo",
1167d2bedfe7SMark Brown 		.id = 2,
1168d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_ldo2_resources),
1169d2bedfe7SMark Brown 		.resources = wm831x_ldo2_resources,
1170d2bedfe7SMark Brown 	},
1171d2bedfe7SMark Brown 	{
1172d2bedfe7SMark Brown 		.name = "wm831x-ldo",
1173d2bedfe7SMark Brown 		.id = 3,
1174d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_ldo3_resources),
1175d2bedfe7SMark Brown 		.resources = wm831x_ldo3_resources,
1176d2bedfe7SMark Brown 	},
1177d2bedfe7SMark Brown 	{
1178d2bedfe7SMark Brown 		.name = "wm831x-ldo",
1179d2bedfe7SMark Brown 		.id = 4,
1180d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_ldo4_resources),
1181d2bedfe7SMark Brown 		.resources = wm831x_ldo4_resources,
1182d2bedfe7SMark Brown 	},
1183d2bedfe7SMark Brown 	{
1184d2bedfe7SMark Brown 		.name = "wm831x-ldo",
1185d2bedfe7SMark Brown 		.id = 5,
1186d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_ldo5_resources),
1187d2bedfe7SMark Brown 		.resources = wm831x_ldo5_resources,
1188d2bedfe7SMark Brown 	},
1189d2bedfe7SMark Brown 	{
1190d2bedfe7SMark Brown 		.name = "wm831x-ldo",
1191d2bedfe7SMark Brown 		.id = 6,
1192d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_ldo6_resources),
1193d2bedfe7SMark Brown 		.resources = wm831x_ldo6_resources,
1194d2bedfe7SMark Brown 	},
1195d2bedfe7SMark Brown 	{
1196d2bedfe7SMark Brown 		.name = "wm831x-aldo",
1197d2bedfe7SMark Brown 		.id = 7,
1198d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_ldo7_resources),
1199d2bedfe7SMark Brown 		.resources = wm831x_ldo7_resources,
1200d2bedfe7SMark Brown 	},
1201d2bedfe7SMark Brown 	{
1202d2bedfe7SMark Brown 		.name = "wm831x-aldo",
1203d2bedfe7SMark Brown 		.id = 8,
1204d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_ldo8_resources),
1205d2bedfe7SMark Brown 		.resources = wm831x_ldo8_resources,
1206d2bedfe7SMark Brown 	},
1207d2bedfe7SMark Brown 	{
1208d2bedfe7SMark Brown 		.name = "wm831x-aldo",
1209d2bedfe7SMark Brown 		.id = 9,
1210d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_ldo9_resources),
1211d2bedfe7SMark Brown 		.resources = wm831x_ldo9_resources,
1212d2bedfe7SMark Brown 	},
1213d2bedfe7SMark Brown 	{
1214d2bedfe7SMark Brown 		.name = "wm831x-aldo",
1215d2bedfe7SMark Brown 		.id = 10,
1216d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_ldo10_resources),
1217d2bedfe7SMark Brown 		.resources = wm831x_ldo10_resources,
1218d2bedfe7SMark Brown 	},
1219d2bedfe7SMark Brown 	{
1220d2bedfe7SMark Brown 		.name = "wm831x-alive-ldo",
1221d2bedfe7SMark Brown 		.id = 11,
1222d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_ldo11_resources),
1223d2bedfe7SMark Brown 		.resources = wm831x_ldo11_resources,
1224d2bedfe7SMark Brown 	},
1225d2bedfe7SMark Brown 	{
1226d2bedfe7SMark Brown 		.name = "wm831x-on",
1227d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_on_resources),
1228d2bedfe7SMark Brown 		.resources = wm831x_on_resources,
1229d2bedfe7SMark Brown 	},
1230d2bedfe7SMark Brown 	{
1231d2bedfe7SMark Brown 		.name = "wm831x-power",
1232d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_power_resources),
1233d2bedfe7SMark Brown 		.resources = wm831x_power_resources,
1234d2bedfe7SMark Brown 	},
1235d2bedfe7SMark Brown 	{
1236d2bedfe7SMark Brown 		.name = "wm831x-rtc",
1237d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_rtc_resources),
1238d2bedfe7SMark Brown 		.resources = wm831x_rtc_resources,
1239d2bedfe7SMark Brown 	},
1240d2bedfe7SMark Brown 	{
1241d2bedfe7SMark Brown 		.name = "wm831x-status",
1242d2bedfe7SMark Brown 		.id = 1,
1243d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_status1_resources),
1244d2bedfe7SMark Brown 		.resources = wm831x_status1_resources,
1245d2bedfe7SMark Brown 	},
1246d2bedfe7SMark Brown 	{
1247d2bedfe7SMark Brown 		.name = "wm831x-status",
1248d2bedfe7SMark Brown 		.id = 2,
1249d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_status2_resources),
1250d2bedfe7SMark Brown 		.resources = wm831x_status2_resources,
1251d2bedfe7SMark Brown 	},
1252d2bedfe7SMark Brown 	{
1253d2bedfe7SMark Brown 		.name = "wm831x-touch",
1254d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_touch_resources),
1255d2bedfe7SMark Brown 		.resources = wm831x_touch_resources,
1256d2bedfe7SMark Brown 	},
1257d2bedfe7SMark Brown 	{
1258d2bedfe7SMark Brown 		.name = "wm831x-watchdog",
1259d2bedfe7SMark Brown 		.num_resources = ARRAY_SIZE(wm831x_wdt_resources),
1260d2bedfe7SMark Brown 		.resources = wm831x_wdt_resources,
1261d2bedfe7SMark Brown 	},
1262d2bedfe7SMark Brown };
1263d2bedfe7SMark Brown 
1264d4e0a89eSMark Brown static struct mfd_cell wm8320_devs[] = {
1265d4e0a89eSMark Brown 	{
1266d4e0a89eSMark Brown 		.name = "wm831x-backup",
1267d4e0a89eSMark Brown 	},
1268d4e0a89eSMark Brown 	{
1269d4e0a89eSMark Brown 		.name = "wm831x-buckv",
1270d4e0a89eSMark Brown 		.id = 1,
1271d4e0a89eSMark Brown 		.num_resources = ARRAY_SIZE(wm831x_dcdc1_resources),
1272d4e0a89eSMark Brown 		.resources = wm831x_dcdc1_resources,
1273d4e0a89eSMark Brown 	},
1274d4e0a89eSMark Brown 	{
1275d4e0a89eSMark Brown 		.name = "wm831x-buckv",
1276d4e0a89eSMark Brown 		.id = 2,
1277d4e0a89eSMark Brown 		.num_resources = ARRAY_SIZE(wm831x_dcdc2_resources),
1278d4e0a89eSMark Brown 		.resources = wm831x_dcdc2_resources,
1279d4e0a89eSMark Brown 	},
1280d4e0a89eSMark Brown 	{
1281d4e0a89eSMark Brown 		.name = "wm831x-buckp",
1282d4e0a89eSMark Brown 		.id = 3,
1283d4e0a89eSMark Brown 		.num_resources = ARRAY_SIZE(wm831x_dcdc3_resources),
1284d4e0a89eSMark Brown 		.resources = wm831x_dcdc3_resources,
1285d4e0a89eSMark Brown 	},
1286d4e0a89eSMark Brown 	{
1287d4e0a89eSMark Brown 		.name = "wm831x-buckp",
1288d4e0a89eSMark Brown 		.id = 4,
1289d4e0a89eSMark Brown 		.num_resources = ARRAY_SIZE(wm8320_dcdc4_buck_resources),
1290d4e0a89eSMark Brown 		.resources = wm8320_dcdc4_buck_resources,
1291d4e0a89eSMark Brown 	},
1292d4e0a89eSMark Brown 	{
1293d4e0a89eSMark Brown 		.name = "wm831x-gpio",
1294d4e0a89eSMark Brown 		.num_resources = ARRAY_SIZE(wm831x_gpio_resources),
1295d4e0a89eSMark Brown 		.resources = wm831x_gpio_resources,
1296d4e0a89eSMark Brown 	},
1297d4e0a89eSMark Brown 	{
1298d4e0a89eSMark Brown 		.name = "wm831x-hwmon",
1299d4e0a89eSMark Brown 	},
1300d4e0a89eSMark Brown 	{
1301d4e0a89eSMark Brown 		.name = "wm831x-ldo",
1302d4e0a89eSMark Brown 		.id = 1,
1303d4e0a89eSMark Brown 		.num_resources = ARRAY_SIZE(wm831x_ldo1_resources),
1304d4e0a89eSMark Brown 		.resources = wm831x_ldo1_resources,
1305d4e0a89eSMark Brown 	},
1306d4e0a89eSMark Brown 	{
1307d4e0a89eSMark Brown 		.name = "wm831x-ldo",
1308d4e0a89eSMark Brown 		.id = 2,
1309d4e0a89eSMark Brown 		.num_resources = ARRAY_SIZE(wm831x_ldo2_resources),
1310d4e0a89eSMark Brown 		.resources = wm831x_ldo2_resources,
1311d4e0a89eSMark Brown 	},
1312d4e0a89eSMark Brown 	{
1313d4e0a89eSMark Brown 		.name = "wm831x-ldo",
1314d4e0a89eSMark Brown 		.id = 3,
1315d4e0a89eSMark Brown 		.num_resources = ARRAY_SIZE(wm831x_ldo3_resources),
1316d4e0a89eSMark Brown 		.resources = wm831x_ldo3_resources,
1317d4e0a89eSMark Brown 	},
1318d4e0a89eSMark Brown 	{
1319d4e0a89eSMark Brown 		.name = "wm831x-ldo",
1320d4e0a89eSMark Brown 		.id = 4,
1321d4e0a89eSMark Brown 		.num_resources = ARRAY_SIZE(wm831x_ldo4_resources),
1322d4e0a89eSMark Brown 		.resources = wm831x_ldo4_resources,
1323d4e0a89eSMark Brown 	},
1324d4e0a89eSMark Brown 	{
1325d4e0a89eSMark Brown 		.name = "wm831x-ldo",
1326d4e0a89eSMark Brown 		.id = 5,
1327d4e0a89eSMark Brown 		.num_resources = ARRAY_SIZE(wm831x_ldo5_resources),
1328d4e0a89eSMark Brown 		.resources = wm831x_ldo5_resources,
1329d4e0a89eSMark Brown 	},
1330d4e0a89eSMark Brown 	{
1331d4e0a89eSMark Brown 		.name = "wm831x-ldo",
1332d4e0a89eSMark Brown 		.id = 6,
1333d4e0a89eSMark Brown 		.num_resources = ARRAY_SIZE(wm831x_ldo6_resources),
1334d4e0a89eSMark Brown 		.resources = wm831x_ldo6_resources,
1335d4e0a89eSMark Brown 	},
1336d4e0a89eSMark Brown 	{
1337d4e0a89eSMark Brown 		.name = "wm831x-aldo",
1338d4e0a89eSMark Brown 		.id = 7,
1339d4e0a89eSMark Brown 		.num_resources = ARRAY_SIZE(wm831x_ldo7_resources),
1340d4e0a89eSMark Brown 		.resources = wm831x_ldo7_resources,
1341d4e0a89eSMark Brown 	},
1342d4e0a89eSMark Brown 	{
1343d4e0a89eSMark Brown 		.name = "wm831x-aldo",
1344d4e0a89eSMark Brown 		.id = 8,
1345d4e0a89eSMark Brown 		.num_resources = ARRAY_SIZE(wm831x_ldo8_resources),
1346d4e0a89eSMark Brown 		.resources = wm831x_ldo8_resources,
1347d4e0a89eSMark Brown 	},
1348d4e0a89eSMark Brown 	{
1349d4e0a89eSMark Brown 		.name = "wm831x-aldo",
1350d4e0a89eSMark Brown 		.id = 9,
1351d4e0a89eSMark Brown 		.num_resources = ARRAY_SIZE(wm831x_ldo9_resources),
1352d4e0a89eSMark Brown 		.resources = wm831x_ldo9_resources,
1353d4e0a89eSMark Brown 	},
1354d4e0a89eSMark Brown 	{
1355d4e0a89eSMark Brown 		.name = "wm831x-aldo",
1356d4e0a89eSMark Brown 		.id = 10,
1357d4e0a89eSMark Brown 		.num_resources = ARRAY_SIZE(wm831x_ldo10_resources),
1358d4e0a89eSMark Brown 		.resources = wm831x_ldo10_resources,
1359d4e0a89eSMark Brown 	},
1360d4e0a89eSMark Brown 	{
1361d4e0a89eSMark Brown 		.name = "wm831x-alive-ldo",
1362d4e0a89eSMark Brown 		.id = 11,
1363d4e0a89eSMark Brown 		.num_resources = ARRAY_SIZE(wm831x_ldo11_resources),
1364d4e0a89eSMark Brown 		.resources = wm831x_ldo11_resources,
1365d4e0a89eSMark Brown 	},
1366d4e0a89eSMark Brown 	{
1367d4e0a89eSMark Brown 		.name = "wm831x-on",
1368d4e0a89eSMark Brown 		.num_resources = ARRAY_SIZE(wm831x_on_resources),
1369d4e0a89eSMark Brown 		.resources = wm831x_on_resources,
1370d4e0a89eSMark Brown 	},
1371d4e0a89eSMark Brown 	{
1372d4e0a89eSMark Brown 		.name = "wm831x-rtc",
1373d4e0a89eSMark Brown 		.num_resources = ARRAY_SIZE(wm831x_rtc_resources),
1374d4e0a89eSMark Brown 		.resources = wm831x_rtc_resources,
1375d4e0a89eSMark Brown 	},
1376d4e0a89eSMark Brown 	{
1377d4e0a89eSMark Brown 		.name = "wm831x-status",
1378d4e0a89eSMark Brown 		.id = 1,
1379d4e0a89eSMark Brown 		.num_resources = ARRAY_SIZE(wm831x_status1_resources),
1380d4e0a89eSMark Brown 		.resources = wm831x_status1_resources,
1381d4e0a89eSMark Brown 	},
1382d4e0a89eSMark Brown 	{
1383d4e0a89eSMark Brown 		.name = "wm831x-status",
1384d4e0a89eSMark Brown 		.id = 2,
1385d4e0a89eSMark Brown 		.num_resources = ARRAY_SIZE(wm831x_status2_resources),
1386d4e0a89eSMark Brown 		.resources = wm831x_status2_resources,
1387d4e0a89eSMark Brown 	},
1388d4e0a89eSMark Brown 	{
1389d4e0a89eSMark Brown 		.name = "wm831x-watchdog",
1390d4e0a89eSMark Brown 		.num_resources = ARRAY_SIZE(wm831x_wdt_resources),
1391d4e0a89eSMark Brown 		.resources = wm831x_wdt_resources,
1392d4e0a89eSMark Brown 	},
1393d4e0a89eSMark Brown };
1394d4e0a89eSMark Brown 
139563aed85eSMark Brown static struct mfd_cell backlight_devs[] = {
139663aed85eSMark Brown 	{
139763aed85eSMark Brown 		.name = "wm831x-backlight",
139863aed85eSMark Brown 	},
139963aed85eSMark Brown };
140063aed85eSMark Brown 
1401d2bedfe7SMark Brown /*
1402d2bedfe7SMark Brown  * Instantiate the generic non-control parts of the device.
1403d2bedfe7SMark Brown  */
1404d2bedfe7SMark Brown static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
1405d2bedfe7SMark Brown {
1406d2bedfe7SMark Brown 	struct wm831x_pdata *pdata = wm831x->dev->platform_data;
1407d2bedfe7SMark Brown 	int rev;
1408d2bedfe7SMark Brown 	enum wm831x_parent parent;
1409d2bedfe7SMark Brown 	int ret;
1410d2bedfe7SMark Brown 
1411d2bedfe7SMark Brown 	mutex_init(&wm831x->io_lock);
1412d2bedfe7SMark Brown 	mutex_init(&wm831x->key_lock);
14137e9f9fd4SMark Brown 	mutex_init(&wm831x->auxadc_lock);
1414d2bedfe7SMark Brown 	dev_set_drvdata(wm831x->dev, wm831x);
1415d2bedfe7SMark Brown 
1416d2bedfe7SMark Brown 	ret = wm831x_reg_read(wm831x, WM831X_PARENT_ID);
1417d2bedfe7SMark Brown 	if (ret < 0) {
1418d2bedfe7SMark Brown 		dev_err(wm831x->dev, "Failed to read parent ID: %d\n", ret);
1419d2bedfe7SMark Brown 		goto err;
1420d2bedfe7SMark Brown 	}
1421d2bedfe7SMark Brown 	if (ret != 0x6204) {
1422d2bedfe7SMark Brown 		dev_err(wm831x->dev, "Device is not a WM831x: ID %x\n", ret);
1423d2bedfe7SMark Brown 		ret = -EINVAL;
1424d2bedfe7SMark Brown 		goto err;
1425d2bedfe7SMark Brown 	}
1426d2bedfe7SMark Brown 
1427d2bedfe7SMark Brown 	ret = wm831x_reg_read(wm831x, WM831X_REVISION);
1428d2bedfe7SMark Brown 	if (ret < 0) {
1429d2bedfe7SMark Brown 		dev_err(wm831x->dev, "Failed to read revision: %d\n", ret);
1430d2bedfe7SMark Brown 		goto err;
1431d2bedfe7SMark Brown 	}
1432d2bedfe7SMark Brown 	rev = (ret & WM831X_PARENT_REV_MASK) >> WM831X_PARENT_REV_SHIFT;
1433d2bedfe7SMark Brown 
1434d2bedfe7SMark Brown 	ret = wm831x_reg_read(wm831x, WM831X_RESET_ID);
1435d2bedfe7SMark Brown 	if (ret < 0) {
1436d2bedfe7SMark Brown 		dev_err(wm831x->dev, "Failed to read device ID: %d\n", ret);
1437d2bedfe7SMark Brown 		goto err;
1438d2bedfe7SMark Brown 	}
1439d2bedfe7SMark Brown 
1440894362f5SMark Brown 	/* Some engineering samples do not have the ID set, rely on
1441894362f5SMark Brown 	 * the device being registered correctly.
1442d2bedfe7SMark Brown 	 */
1443894362f5SMark Brown 	if (ret == 0) {
1444894362f5SMark Brown 		dev_info(wm831x->dev, "Device is an engineering sample\n");
1445894362f5SMark Brown 		ret = id;
1446d2bedfe7SMark Brown 	}
1447894362f5SMark Brown 
1448894362f5SMark Brown 	switch (ret) {
1449894362f5SMark Brown 	case WM8310:
1450894362f5SMark Brown 		parent = WM8310;
14516f2ecaaeSMark Brown 		wm831x->num_gpio = 16;
1452f92e8f81SMark Brown 		if (rev > 0) {
1453f92e8f81SMark Brown 			wm831x->has_gpio_ena = 1;
1454f92e8f81SMark Brown 			wm831x->has_cs_sts = 1;
1455f92e8f81SMark Brown 		}
1456f92e8f81SMark Brown 
1457894362f5SMark Brown 		dev_info(wm831x->dev, "WM8310 revision %c\n", 'A' + rev);
1458894362f5SMark Brown 		break;
1459894362f5SMark Brown 
1460894362f5SMark Brown 	case WM8311:
1461894362f5SMark Brown 		parent = WM8311;
14626f2ecaaeSMark Brown 		wm831x->num_gpio = 16;
1463f92e8f81SMark Brown 		if (rev > 0) {
1464f92e8f81SMark Brown 			wm831x->has_gpio_ena = 1;
1465f92e8f81SMark Brown 			wm831x->has_cs_sts = 1;
1466f92e8f81SMark Brown 		}
1467f92e8f81SMark Brown 
1468894362f5SMark Brown 		dev_info(wm831x->dev, "WM8311 revision %c\n", 'A' + rev);
1469894362f5SMark Brown 		break;
1470894362f5SMark Brown 
1471894362f5SMark Brown 	case WM8312:
1472894362f5SMark Brown 		parent = WM8312;
14736f2ecaaeSMark Brown 		wm831x->num_gpio = 16;
1474f92e8f81SMark Brown 		if (rev > 0) {
1475f92e8f81SMark Brown 			wm831x->has_gpio_ena = 1;
1476f92e8f81SMark Brown 			wm831x->has_cs_sts = 1;
1477f92e8f81SMark Brown 		}
1478f92e8f81SMark Brown 
1479894362f5SMark Brown 		dev_info(wm831x->dev, "WM8312 revision %c\n", 'A' + rev);
1480d2bedfe7SMark Brown 		break;
1481d2bedfe7SMark Brown 
1482d4e0a89eSMark Brown 	case WM8320:
1483d4e0a89eSMark Brown 		parent = WM8320;
1484d4e0a89eSMark Brown 		wm831x->num_gpio = 12;
1485d4e0a89eSMark Brown 		dev_info(wm831x->dev, "WM8320 revision %c\n", 'A' + rev);
1486d4e0a89eSMark Brown 		break;
1487d4e0a89eSMark Brown 
1488d2bedfe7SMark Brown 	default:
1489d2bedfe7SMark Brown 		dev_err(wm831x->dev, "Unknown WM831x device %04x\n", ret);
1490d2bedfe7SMark Brown 		ret = -EINVAL;
1491d2bedfe7SMark Brown 		goto err;
1492d2bedfe7SMark Brown 	}
1493d2bedfe7SMark Brown 
1494d2bedfe7SMark Brown 	/* This will need revisiting in future but is OK for all
1495d2bedfe7SMark Brown 	 * current parts.
1496d2bedfe7SMark Brown 	 */
1497d2bedfe7SMark Brown 	if (parent != id)
1498894362f5SMark Brown 		dev_warn(wm831x->dev, "Device was registered as a WM%lx\n",
1499d2bedfe7SMark Brown 			 id);
1500d2bedfe7SMark Brown 
1501d2bedfe7SMark Brown 	/* Bootstrap the user key */
1502d2bedfe7SMark Brown 	ret = wm831x_reg_read(wm831x, WM831X_SECURITY_KEY);
1503d2bedfe7SMark Brown 	if (ret < 0) {
1504d2bedfe7SMark Brown 		dev_err(wm831x->dev, "Failed to read security key: %d\n", ret);
1505d2bedfe7SMark Brown 		goto err;
1506d2bedfe7SMark Brown 	}
1507d2bedfe7SMark Brown 	if (ret != 0) {
1508d2bedfe7SMark Brown 		dev_warn(wm831x->dev, "Security key had non-zero value %x\n",
1509d2bedfe7SMark Brown 			 ret);
1510d2bedfe7SMark Brown 		wm831x_reg_write(wm831x, WM831X_SECURITY_KEY, 0);
1511d2bedfe7SMark Brown 	}
1512d2bedfe7SMark Brown 	wm831x->locked = 1;
1513d2bedfe7SMark Brown 
1514d2bedfe7SMark Brown 	if (pdata && pdata->pre_init) {
1515d2bedfe7SMark Brown 		ret = pdata->pre_init(wm831x);
1516d2bedfe7SMark Brown 		if (ret != 0) {
1517d2bedfe7SMark Brown 			dev_err(wm831x->dev, "pre_init() failed: %d\n", ret);
1518d2bedfe7SMark Brown 			goto err;
1519d2bedfe7SMark Brown 		}
1520d2bedfe7SMark Brown 	}
1521d2bedfe7SMark Brown 
15227d4d0a3eSMark Brown 	ret = wm831x_irq_init(wm831x, irq);
15237d4d0a3eSMark Brown 	if (ret != 0)
15247d4d0a3eSMark Brown 		goto err;
15257d4d0a3eSMark Brown 
1526d2bedfe7SMark Brown 	/* The core device is up, instantiate the subdevices. */
1527d2bedfe7SMark Brown 	switch (parent) {
1528d2bedfe7SMark Brown 	case WM8310:
1529d2bedfe7SMark Brown 		ret = mfd_add_devices(wm831x->dev, -1,
1530d2bedfe7SMark Brown 				      wm8310_devs, ARRAY_SIZE(wm8310_devs),
15315fb4d38bSMark Brown 				      NULL, wm831x->irq_base);
1532d2bedfe7SMark Brown 		break;
1533d2bedfe7SMark Brown 
1534d2bedfe7SMark Brown 	case WM8311:
1535d2bedfe7SMark Brown 		ret = mfd_add_devices(wm831x->dev, -1,
1536d2bedfe7SMark Brown 				      wm8311_devs, ARRAY_SIZE(wm8311_devs),
15375fb4d38bSMark Brown 				      NULL, wm831x->irq_base);
1538d2bedfe7SMark Brown 		break;
1539d2bedfe7SMark Brown 
1540d2bedfe7SMark Brown 	case WM8312:
1541d2bedfe7SMark Brown 		ret = mfd_add_devices(wm831x->dev, -1,
1542d2bedfe7SMark Brown 				      wm8312_devs, ARRAY_SIZE(wm8312_devs),
15435fb4d38bSMark Brown 				      NULL, wm831x->irq_base);
1544d2bedfe7SMark Brown 		break;
1545d2bedfe7SMark Brown 
1546d4e0a89eSMark Brown 	case WM8320:
1547d4e0a89eSMark Brown 		ret = mfd_add_devices(wm831x->dev, -1,
1548d4e0a89eSMark Brown 				      wm8320_devs, ARRAY_SIZE(wm8320_devs),
1549d4e0a89eSMark Brown 				      NULL, 0);
1550d4e0a89eSMark Brown 		break;
1551d4e0a89eSMark Brown 
1552d2bedfe7SMark Brown 	default:
1553d2bedfe7SMark Brown 		/* If this happens the bus probe function is buggy */
1554d2bedfe7SMark Brown 		BUG();
1555d2bedfe7SMark Brown 	}
1556d2bedfe7SMark Brown 
1557d2bedfe7SMark Brown 	if (ret != 0) {
1558d2bedfe7SMark Brown 		dev_err(wm831x->dev, "Failed to add children\n");
15597d4d0a3eSMark Brown 		goto err_irq;
1560d2bedfe7SMark Brown 	}
1561d2bedfe7SMark Brown 
156263aed85eSMark Brown 	if (pdata && pdata->backlight) {
156363aed85eSMark Brown 		/* Treat errors as non-critical */
156463aed85eSMark Brown 		ret = mfd_add_devices(wm831x->dev, -1, backlight_devs,
15655fb4d38bSMark Brown 				      ARRAY_SIZE(backlight_devs), NULL,
15665fb4d38bSMark Brown 				      wm831x->irq_base);
156763aed85eSMark Brown 		if (ret < 0)
156863aed85eSMark Brown 			dev_err(wm831x->dev, "Failed to add backlight: %d\n",
156963aed85eSMark Brown 				ret);
157063aed85eSMark Brown 	}
157163aed85eSMark Brown 
15726704e517SMark Brown 	wm831x_otp_init(wm831x);
15736704e517SMark Brown 
1574d2bedfe7SMark Brown 	if (pdata && pdata->post_init) {
1575d2bedfe7SMark Brown 		ret = pdata->post_init(wm831x);
1576d2bedfe7SMark Brown 		if (ret != 0) {
1577d2bedfe7SMark Brown 			dev_err(wm831x->dev, "post_init() failed: %d\n", ret);
15787d4d0a3eSMark Brown 			goto err_irq;
1579d2bedfe7SMark Brown 		}
1580d2bedfe7SMark Brown 	}
1581d2bedfe7SMark Brown 
1582d2bedfe7SMark Brown 	return 0;
1583d2bedfe7SMark Brown 
15847d4d0a3eSMark Brown err_irq:
15857d4d0a3eSMark Brown 	wm831x_irq_exit(wm831x);
1586d2bedfe7SMark Brown err:
1587d2bedfe7SMark Brown 	mfd_remove_devices(wm831x->dev);
1588d2bedfe7SMark Brown 	kfree(wm831x);
1589d2bedfe7SMark Brown 	return ret;
1590d2bedfe7SMark Brown }
1591d2bedfe7SMark Brown 
1592d2bedfe7SMark Brown static void wm831x_device_exit(struct wm831x *wm831x)
1593d2bedfe7SMark Brown {
15946704e517SMark Brown 	wm831x_otp_exit(wm831x);
1595d2bedfe7SMark Brown 	mfd_remove_devices(wm831x->dev);
15967d4d0a3eSMark Brown 	wm831x_irq_exit(wm831x);
1597d2bedfe7SMark Brown 	kfree(wm831x);
1598d2bedfe7SMark Brown }
1599d2bedfe7SMark Brown 
1600d2bedfe7SMark Brown static int wm831x_i2c_read_device(struct wm831x *wm831x, unsigned short reg,
1601d2bedfe7SMark Brown 				  int bytes, void *dest)
1602d2bedfe7SMark Brown {
1603d2bedfe7SMark Brown 	struct i2c_client *i2c = wm831x->control_data;
1604d2bedfe7SMark Brown 	int ret;
1605d2bedfe7SMark Brown 	u16 r = cpu_to_be16(reg);
1606d2bedfe7SMark Brown 
1607d2bedfe7SMark Brown 	ret = i2c_master_send(i2c, (unsigned char *)&r, 2);
1608d2bedfe7SMark Brown 	if (ret < 0)
1609d2bedfe7SMark Brown 		return ret;
1610d2bedfe7SMark Brown 	if (ret != 2)
1611d2bedfe7SMark Brown 		return -EIO;
1612d2bedfe7SMark Brown 
1613d2bedfe7SMark Brown 	ret = i2c_master_recv(i2c, dest, bytes);
1614d2bedfe7SMark Brown 	if (ret < 0)
1615d2bedfe7SMark Brown 		return ret;
1616d2bedfe7SMark Brown 	if (ret != bytes)
1617d2bedfe7SMark Brown 		return -EIO;
1618d2bedfe7SMark Brown 	return 0;
1619d2bedfe7SMark Brown }
1620d2bedfe7SMark Brown 
1621d2bedfe7SMark Brown /* Currently we allocate the write buffer on the stack; this is OK for
1622d2bedfe7SMark Brown  * small writes - if we need to do large writes this will need to be
1623d2bedfe7SMark Brown  * revised.
1624d2bedfe7SMark Brown  */
1625d2bedfe7SMark Brown static int wm831x_i2c_write_device(struct wm831x *wm831x, unsigned short reg,
1626d2bedfe7SMark Brown 				   int bytes, void *src)
1627d2bedfe7SMark Brown {
1628d2bedfe7SMark Brown 	struct i2c_client *i2c = wm831x->control_data;
1629d2bedfe7SMark Brown 	unsigned char msg[bytes + 2];
1630d2bedfe7SMark Brown 	int ret;
1631d2bedfe7SMark Brown 
1632d2bedfe7SMark Brown 	reg = cpu_to_be16(reg);
1633d2bedfe7SMark Brown 	memcpy(&msg[0], &reg, 2);
1634d2bedfe7SMark Brown 	memcpy(&msg[2], src, bytes);
1635d2bedfe7SMark Brown 
1636d2bedfe7SMark Brown 	ret = i2c_master_send(i2c, msg, bytes + 2);
1637d2bedfe7SMark Brown 	if (ret < 0)
1638d2bedfe7SMark Brown 		return ret;
1639d2bedfe7SMark Brown 	if (ret < bytes + 2)
1640d2bedfe7SMark Brown 		return -EIO;
1641d2bedfe7SMark Brown 
1642d2bedfe7SMark Brown 	return 0;
1643d2bedfe7SMark Brown }
1644d2bedfe7SMark Brown 
1645d2bedfe7SMark Brown static int wm831x_i2c_probe(struct i2c_client *i2c,
1646d2bedfe7SMark Brown 			    const struct i2c_device_id *id)
1647d2bedfe7SMark Brown {
1648d2bedfe7SMark Brown 	struct wm831x *wm831x;
1649d2bedfe7SMark Brown 
1650d2bedfe7SMark Brown 	wm831x = kzalloc(sizeof(struct wm831x), GFP_KERNEL);
1651d2bedfe7SMark Brown 	if (wm831x == NULL) {
1652d2bedfe7SMark Brown 		kfree(i2c);
1653d2bedfe7SMark Brown 		return -ENOMEM;
1654d2bedfe7SMark Brown 	}
1655d2bedfe7SMark Brown 
1656d2bedfe7SMark Brown 	i2c_set_clientdata(i2c, wm831x);
1657d2bedfe7SMark Brown 	wm831x->dev = &i2c->dev;
1658d2bedfe7SMark Brown 	wm831x->control_data = i2c;
1659d2bedfe7SMark Brown 	wm831x->read_dev = wm831x_i2c_read_device;
1660d2bedfe7SMark Brown 	wm831x->write_dev = wm831x_i2c_write_device;
1661d2bedfe7SMark Brown 
1662d2bedfe7SMark Brown 	return wm831x_device_init(wm831x, id->driver_data, i2c->irq);
1663d2bedfe7SMark Brown }
1664d2bedfe7SMark Brown 
1665d2bedfe7SMark Brown static int wm831x_i2c_remove(struct i2c_client *i2c)
1666d2bedfe7SMark Brown {
1667d2bedfe7SMark Brown 	struct wm831x *wm831x = i2c_get_clientdata(i2c);
1668d2bedfe7SMark Brown 
1669d2bedfe7SMark Brown 	wm831x_device_exit(wm831x);
1670d2bedfe7SMark Brown 
1671d2bedfe7SMark Brown 	return 0;
1672d2bedfe7SMark Brown }
1673d2bedfe7SMark Brown 
1674d2bedfe7SMark Brown static const struct i2c_device_id wm831x_i2c_id[] = {
1675d2bedfe7SMark Brown 	{ "wm8310", WM8310 },
1676d2bedfe7SMark Brown 	{ "wm8311", WM8311 },
1677d2bedfe7SMark Brown 	{ "wm8312", WM8312 },
1678d4e0a89eSMark Brown 	{ "wm8320", WM8320 },
1679d2bedfe7SMark Brown 	{ }
1680d2bedfe7SMark Brown };
1681d2bedfe7SMark Brown MODULE_DEVICE_TABLE(i2c, wm831x_i2c_id);
1682d2bedfe7SMark Brown 
1683d2bedfe7SMark Brown 
1684d2bedfe7SMark Brown static struct i2c_driver wm831x_i2c_driver = {
1685d2bedfe7SMark Brown 	.driver = {
1686d2bedfe7SMark Brown 		   .name = "wm831x",
1687d2bedfe7SMark Brown 		   .owner = THIS_MODULE,
1688d2bedfe7SMark Brown 	},
1689d2bedfe7SMark Brown 	.probe = wm831x_i2c_probe,
1690d2bedfe7SMark Brown 	.remove = wm831x_i2c_remove,
1691d2bedfe7SMark Brown 	.id_table = wm831x_i2c_id,
1692d2bedfe7SMark Brown };
1693d2bedfe7SMark Brown 
1694d2bedfe7SMark Brown static int __init wm831x_i2c_init(void)
1695d2bedfe7SMark Brown {
1696d2bedfe7SMark Brown 	int ret;
1697d2bedfe7SMark Brown 
1698d2bedfe7SMark Brown 	ret = i2c_add_driver(&wm831x_i2c_driver);
1699d2bedfe7SMark Brown 	if (ret != 0)
1700d2bedfe7SMark Brown 		pr_err("Failed to register wm831x I2C driver: %d\n", ret);
1701d2bedfe7SMark Brown 
1702d2bedfe7SMark Brown 	return ret;
1703d2bedfe7SMark Brown }
1704d2bedfe7SMark Brown subsys_initcall(wm831x_i2c_init);
1705d2bedfe7SMark Brown 
1706d2bedfe7SMark Brown static void __exit wm831x_i2c_exit(void)
1707d2bedfe7SMark Brown {
1708d2bedfe7SMark Brown 	i2c_del_driver(&wm831x_i2c_driver);
1709d2bedfe7SMark Brown }
1710d2bedfe7SMark Brown module_exit(wm831x_i2c_exit);
1711d2bedfe7SMark Brown 
1712d2bedfe7SMark Brown MODULE_DESCRIPTION("I2C support for the WM831X AudioPlus PMIC");
1713d2bedfe7SMark Brown MODULE_LICENSE("GPL");
1714d2bedfe7SMark Brown MODULE_AUTHOR("Mark Brown");
1715