xref: /openbsd-src/sys/dev/fdt/rkpmic.c (revision 32a67d492cfdc7c31a8f25d7f6b7dbe72d1a282a)
1*32a67d49Skettenis /*	$OpenBSD: rkpmic.c,v 1.18 2024/11/23 21:24:03 kettenis Exp $	*/
2ad688f68Skettenis /*
3ad688f68Skettenis  * Copyright (c) 2017 Mark Kettenis <kettenis@openbsd.org>
4ad688f68Skettenis  *
5ad688f68Skettenis  * Permission to use, copy, modify, and distribute this software for any
6ad688f68Skettenis  * purpose with or without fee is hereby granted, provided that the above
7ad688f68Skettenis  * copyright notice and this permission notice appear in all copies.
8ad688f68Skettenis  *
9ad688f68Skettenis  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10ad688f68Skettenis  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11ad688f68Skettenis  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12ad688f68Skettenis  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13ad688f68Skettenis  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14ad688f68Skettenis  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15ad688f68Skettenis  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16ad688f68Skettenis  */
17ad688f68Skettenis 
18ad688f68Skettenis #include <sys/param.h>
19ad688f68Skettenis #include <sys/systm.h>
20ad688f68Skettenis #include <sys/device.h>
2192bce581Skettenis #include <sys/malloc.h>
2230293cdcSkettenis #include <sys/proc.h>
2330293cdcSkettenis #include <sys/signalvar.h>
2430293cdcSkettenis 
2530293cdcSkettenis #include <machine/fdt.h>
26ad688f68Skettenis 
27ad688f68Skettenis #include <dev/ofw/openfirm.h>
2892bce581Skettenis #include <dev/ofw/ofw_regulator.h>
29ad688f68Skettenis #include <dev/ofw/fdt.h>
30ad688f68Skettenis 
31ad688f68Skettenis #include <dev/i2c/i2cvar.h>
32ca857453Skettenis #include <dev/spi/spivar.h>
33ad688f68Skettenis 
34ad688f68Skettenis #include <dev/clock_subr.h>
35ad688f68Skettenis 
36*32a67d49Skettenis extern void (*powerdownfn)(void);
37*32a67d49Skettenis 
38c23d9011Skurt #define RK80X_SECONDS		0x00
39c23d9011Skurt #define RK80X_MINUTES		0x01
40c23d9011Skurt #define RK80X_HOURS		0x02
41c23d9011Skurt #define RK80X_DAYS		0x03
42c23d9011Skurt #define RK80X_MONTHS		0x04
43c23d9011Skurt #define RK80X_YEARS		0x05
44c23d9011Skurt #define RK80X_WEEKS		0x06
45c23d9011Skurt #define RK80X_NRTC_REGS	7
46ad688f68Skettenis 
47c23d9011Skurt #define RK805_RTC_CTRL		0x10
48c23d9011Skurt #define RK808_RTC_CTRL		0x10
49c23d9011Skurt #define RK809_RTC_CTRL		0x0d
50c23d9011Skurt #define  RK80X_RTC_CTRL_STOP_RTC	0x01
51c23d9011Skurt 
52c23d9011Skurt #define RK805_RTC_STATUS	0x11
53c23d9011Skurt #define RK808_RTC_STATUS	0x11
54c23d9011Skurt #define RK809_RTC_STATUS	0x0e
55c23d9011Skurt #define  RK80X_RTC_STATUS_POWER_UP	0x80
56c23d9011Skurt 
57*32a67d49Skettenis #define RK805_DEV_CTRL		0x4b
58*32a67d49Skettenis #define  RK805_DEV_CTRL_DEV_OFF	0x01
59*32a67d49Skettenis 
60*32a67d49Skettenis #define RK806_SYS_CFG3		0x72
61*32a67d49Skettenis #define  RK806_SYS_CFG3_DEV_OFF	0x01
62*32a67d49Skettenis 
63*32a67d49Skettenis #define RK808_DEVCTRL		0x4b
64*32a67d49Skettenis #define  RK808_DEVCTRL_DEV_OFF_RST	0x08
65*32a67d49Skettenis 
6630293cdcSkettenis #define RK809_PMIC_SYS_CFG3	0xf4
6730293cdcSkettenis #define  RK809_PMIC_SYS_CFG3_SLP_FUN_MASK	0x18
6830293cdcSkettenis #define  RK809_PMIC_SYS_CFG3_SLP_FUN_NONE	0x00
6930293cdcSkettenis #define  RK809_PMIC_SYS_CFG3_SLP_FUN_SLEEP	0x08
70*32a67d49Skettenis #define  RK809_PMIC_SYS_CFG3_DEV_OFF		0x01
7130293cdcSkettenis #define RK809_PMIC_INT_STS0	0xf8
7230293cdcSkettenis #define RK809_PMIC_INT_MSK0	0xf9
7330293cdcSkettenis #define  RK809_PMIC_INT_MSK0_PWRON_FALL_INT_IM	0x01
7430293cdcSkettenis #define RK809_PMIC_INT_STS1	0xfa
7530293cdcSkettenis #define RK809_PMIC_INT_MSK1	0xfb
7630293cdcSkettenis #define RK809_PMIC_INT_STS2	0xfc
7730293cdcSkettenis #define RK809_PMIC_INT_MSK2	0xfd
7830293cdcSkettenis #define RK809_PMIC_GPIO_INT_CONFIG	0xfe
7930293cdcSkettenis #define  RK809_PMIC_GPIO_INT_CONFIG_INT_POL	0x02
8030293cdcSkettenis 
81ca857453Skettenis #define RKSPI_CMD_READ		(0 << 7)
82ca857453Skettenis #define RKSPI_CMD_WRITE		(1 << 7)
83ca857453Skettenis 
84c23d9011Skurt struct rkpmic_vsel_range {
85c23d9011Skurt 	uint32_t base, delta;
86c23d9011Skurt 	uint8_t vsel_min, vsel_max;
87c23d9011Skurt };
88ad688f68Skettenis 
8992bce581Skettenis struct rkpmic_regdata {
9092bce581Skettenis 	const char *name;
91b8599033Skettenis 	uint8_t vreg, vmask;
92b8599033Skettenis 	uint8_t sreg, smask;
9337c734d3Snaddy 	const struct rkpmic_vsel_range *vsel_range;
94c23d9011Skurt };
95c23d9011Skurt 
96c23d9011Skurt /*
97c23d9011Skurt  * Used by RK805 for BUCK1, BUCK2
98c23d9011Skurt  *  0-59:	0.7125V-1.45V, step=12.5mV
99c23d9011Skurt  *  60-62:	1.8V-2.2V, step=200mV
100c23d9011Skurt  *  63:		2.3V
101c23d9011Skurt  */
10237c734d3Snaddy const struct rkpmic_vsel_range rk805_vsel_range1[] = {
103c23d9011Skurt 	{ 712500, 12500, 0, 59 },
104c23d9011Skurt 	{ 1800000, 200000, 60, 62 },
105c23d9011Skurt 	{ 2300000, 0, 63, 63 },
106c23d9011Skurt 	{}
107c23d9011Skurt };
108c23d9011Skurt 
109c23d9011Skurt /*
110c23d9011Skurt  * Used by RK805 for BUCK4
111c23d9011Skurt  *  0-27:	0.8V-3.5V, step=100mV
112c23d9011Skurt  */
11337c734d3Snaddy const struct rkpmic_vsel_range rk805_vsel_range2[] = {
114c23d9011Skurt 	{ 800000, 100000, 0, 27 },
115c23d9011Skurt 	{}
116c23d9011Skurt };
117c23d9011Skurt 
118c23d9011Skurt /*
119c23d9011Skurt  * Used by RK805 for LDO1-3
120c23d9011Skurt  *  0-26:	0.8V-3.4V, step=100mV
121c23d9011Skurt  */
12237c734d3Snaddy const struct rkpmic_vsel_range rk805_vsel_range3[] = {
123c23d9011Skurt 	{ 800000, 100000, 0, 26 },
124c23d9011Skurt 	{}
12592bce581Skettenis };
12692bce581Skettenis 
12737c734d3Snaddy const struct rkpmic_regdata rk805_regdata[] = {
128b8599033Skettenis 	{ "DCDC_REG1", 0x2f, 0x3f, 0, 0, rk805_vsel_range1 },
129b8599033Skettenis 	{ "DCDC_REG2", 0x33, 0x3f, 0, 0, rk805_vsel_range1 },
130b8599033Skettenis 	{ "DCDC_REG4", 0x38, 0x1f, 0, 0, rk805_vsel_range2 },
131b8599033Skettenis 	{ "LDO_REG1", 0x3b, 0x1f, 0, 0, rk805_vsel_range3 },
132b8599033Skettenis 	{ "LDO_REG2", 0x3d, 0x1f, 0, 0, rk805_vsel_range3 },
133b8599033Skettenis 	{ "LDO_REG3", 0x3f, 0x1f, 0, 0, rk805_vsel_range3 },
134c23d9011Skurt 	{ }
135c23d9011Skurt };
136c23d9011Skurt 
137c23d9011Skurt /*
138ca857453Skettenis  * Used by RK806 for BUCK
139ca857453Skettenis  *  0-159:	0.5V-1.5V, step=6.25mV
140ca857453Skettenis  *  160-236:	1.5V-3.4V, step=25mV
141ca857453Skettenis  *  237-255:	3.4V-3.4V, step=0mV
142ca857453Skettenis  */
143ca857453Skettenis const struct rkpmic_vsel_range rk806_vsel_range1[] = {
144ca857453Skettenis 	{ 500000, 6250, 0, 159 },
145ca857453Skettenis 	{ 1500000, 25000, 160, 236 },
146ca857453Skettenis 	{ 3400000, 0, 237, 255 },
147ca857453Skettenis 	{}
148ca857453Skettenis };
149ca857453Skettenis 
150ca857453Skettenis /*
151ca857453Skettenis  * Used by RK806 for LDO
152ca857453Skettenis  *  0-232:	0.5V-3.4V, step=12.5mV
153ca857453Skettenis  *  233-255:	3.4V-3.4V, step=0mV
154ca857453Skettenis  */
155ca857453Skettenis const struct rkpmic_vsel_range rk806_vsel_range2[] = {
156ca857453Skettenis 	{ 500000, 12500, 0, 232 },
157ca857453Skettenis 	{ 3400000, 0, 233, 255 },
158ca857453Skettenis 	{}
159ca857453Skettenis };
160ca857453Skettenis 
161ca857453Skettenis const struct rkpmic_regdata rk806_regdata[] = {
162b8599033Skettenis 	{ "dcdc-reg1", 0x1a, 0xff, 0, 0, rk806_vsel_range1 },
163b8599033Skettenis 	{ "dcdc-reg2", 0x1b, 0xff, 0, 0, rk806_vsel_range1 },
164b8599033Skettenis 	{ "dcdc-reg3", 0x1c, 0xff, 0, 0, rk806_vsel_range1 },
165b8599033Skettenis 	{ "dcdc-reg4", 0x1d, 0xff, 0, 0, rk806_vsel_range1 },
166b8599033Skettenis 	{ "dcdc-reg5", 0x1e, 0xff, 0, 0, rk806_vsel_range1 },
167b8599033Skettenis 	{ "dcdc-reg6", 0x1f, 0xff, 0, 0, rk806_vsel_range1 },
168b8599033Skettenis 	{ "dcdc-reg7", 0x20, 0xff, 0, 0, rk806_vsel_range1 },
169b8599033Skettenis 	{ "dcdc-reg8", 0x21, 0xff, 0, 0, rk806_vsel_range1 },
170b8599033Skettenis 	{ "dcdc-reg9", 0x22, 0xff, 0, 0, rk806_vsel_range1 },
171b8599033Skettenis 	{ "dcdc-reg10", 0x23, 0xff, 0, 0, rk806_vsel_range1 },
172b8599033Skettenis 	{ "nldo-reg1", 0x43, 0xff, 0, 0, rk806_vsel_range2 },
173b8599033Skettenis 	{ "nldo-reg2", 0x44, 0xff, 0, 0, rk806_vsel_range2 },
174b8599033Skettenis 	{ "nldo-reg3", 0x45, 0xff, 0, 0, rk806_vsel_range2 },
175b8599033Skettenis 	{ "nldo-reg4", 0x46, 0xff, 0, 0, rk806_vsel_range2 },
176b8599033Skettenis 	{ "nldo-reg5", 0x47, 0xff, 0, 0, rk806_vsel_range2 },
177b8599033Skettenis 	{ "pldo-reg1", 0x4e, 0xff, 0, 0, rk806_vsel_range2 },
178b8599033Skettenis 	{ "pldo-reg2", 0x4f, 0xff, 0, 0, rk806_vsel_range2 },
179b8599033Skettenis 	{ "pldo-reg3", 0x50, 0xff, 0, 0, rk806_vsel_range2 },
180b8599033Skettenis 	{ "pldo-reg4", 0x51, 0xff, 0, 0, rk806_vsel_range2 },
181b8599033Skettenis 	{ "pldo-reg5", 0x52, 0xff, 0, 0, rk806_vsel_range2 },
182b8599033Skettenis 	{ "pldo-reg6", 0x53, 0xff, 0, 0, rk806_vsel_range2 },
183ca857453Skettenis 	{ }
184ca857453Skettenis };
185ca857453Skettenis 
186ca857453Skettenis /*
187c23d9011Skurt  * Used by RK808 for BUCK1 & BUCK2
188c23d9011Skurt  *  0-63:	0.7125V-1.5V, step=12.5mV
189c23d9011Skurt  */
19037c734d3Snaddy const struct rkpmic_vsel_range rk808_vsel_range1[] = {
191c23d9011Skurt 	{ 712500, 12500, 0, 63 },
192c23d9011Skurt 	{}
193c23d9011Skurt };
194c23d9011Skurt 
195c23d9011Skurt /*
196c23d9011Skurt  * Used by RK808 for BUCK4
197c23d9011Skurt  *  0-15:	1.8V-3.3V,step=100mV
198c23d9011Skurt  */
19937c734d3Snaddy const struct rkpmic_vsel_range rk808_vsel_range2[] = {
200c23d9011Skurt 	{ 1800000, 100000, 0, 15 },
201c23d9011Skurt 	{}
202c23d9011Skurt };
203c23d9011Skurt 
204c23d9011Skurt /*
205c23d9011Skurt  * Used by RK808 for LDO1-2, 4-5, 8
206c23d9011Skurt  *  0-16:	1.8V-3.4V, step=100mV
207c23d9011Skurt  */
20837c734d3Snaddy const struct rkpmic_vsel_range rk808_vsel_range3[] = {
209c23d9011Skurt 	{ 1800000, 100000, 0, 16 },
210c23d9011Skurt 	{}
211c23d9011Skurt };
212c23d9011Skurt 
213c23d9011Skurt /*
214c23d9011Skurt  * Used by RK808 for LDO3
215c23d9011Skurt  *   0-12:	0.8V~2.0V, step=100mV
216c23d9011Skurt  *   13:	2.2V
217c23d9011Skurt  *   15:	2.5V
218c23d9011Skurt  */
21937c734d3Snaddy const struct rkpmic_vsel_range rk808_vsel_range4[] = {
220c23d9011Skurt 	{ 800000, 100000, 0, 12 },
221c23d9011Skurt 	{ 2200000, 0, 13, 13 },
222c23d9011Skurt 	{ 2500000, 0, 15, 15 },
223c23d9011Skurt 	{}
224c23d9011Skurt };
225c23d9011Skurt 
226c23d9011Skurt /*
227c23d9011Skurt  * Used by RK808 for LDO6-7
228c23d9011Skurt  *  0-17:	0.8V-2.5V,step=100mV
229c23d9011Skurt  */
23037c734d3Snaddy const struct rkpmic_vsel_range rk808_vsel_range5[] = {
231c23d9011Skurt 	{ 800000, 100000, 0, 17 },
23243f7f110Skettenis 	{}
23343f7f110Skettenis };
23443f7f110Skettenis 
23537c734d3Snaddy const struct rkpmic_regdata rk808_regdata[] = {
236b8599033Skettenis 	{ "DCDC_REG1", 0x2f, 0x3f, 0, 0, rk808_vsel_range1 },
237b8599033Skettenis 	{ "DCDC_REG2", 0x33, 0x3f, 0, 0, rk808_vsel_range1 },
238b8599033Skettenis 	{ "DCDC_REG4", 0x38, 0x0f, 0, 0, rk808_vsel_range2 },
239b8599033Skettenis 	{ "LDO_REG1", 0x3b, 0x1f, 0, 0, rk808_vsel_range3 },
240b8599033Skettenis 	{ "LDO_REG2", 0x3d, 0x1f, 0, 0, rk808_vsel_range3 },
241b8599033Skettenis 	{ "LDO_REG3", 0x3f, 0x0f, 0, 0, rk808_vsel_range4 },
242b8599033Skettenis 	{ "LDO_REG4", 0x41, 0x1f, 0, 0, rk808_vsel_range3 },
243b8599033Skettenis 	{ "LDO_REG5", 0x43, 0x1f, 0, 0, rk808_vsel_range3 },
244b8599033Skettenis 	{ "LDO_REG6", 0x45, 0x1f, 0, 0, rk808_vsel_range5 },
245b8599033Skettenis 	{ "LDO_REG7", 0x47, 0x1f, 0, 0, rk808_vsel_range5 },
246b8599033Skettenis 	{ "LDO_REG8", 0x49, 0x1f, 0, 0, rk808_vsel_range3 },
247c23d9011Skurt 	{ }
248c23d9011Skurt };
249c23d9011Skurt 
250c23d9011Skurt /*
251c23d9011Skurt  * Used by RK809 for BUCK1-3
252c23d9011Skurt  *  0-80:	0.5V-1.5V,step=12.5mV
253c23d9011Skurt  *  81-89:	1.6V-2.4V,step=100mV
254c23d9011Skurt  */
25537c734d3Snaddy const struct rkpmic_vsel_range rk809_vsel_range1[] = {
256c23d9011Skurt 	{ 500000, 12500, 0, 80 },
257c23d9011Skurt 	{ 1600000, 100000, 81, 89 },
258c23d9011Skurt 	{}
259c23d9011Skurt };
260c23d9011Skurt 
261c23d9011Skurt /*
262c23d9011Skurt  * Used by RK809 for BUCK4
263c23d9011Skurt  *  0-80:	0.5V-1.5V,step=12.5mV
264c23d9011Skurt  *  81-99:	1.6V-3.4V,step=100mV
265c23d9011Skurt  */
26637c734d3Snaddy const struct rkpmic_vsel_range rk809_vsel_range2[] = {
267c23d9011Skurt 	{ 500000, 12500, 0, 80 },
268c23d9011Skurt 	{ 1600000, 100000, 81, 99 },
269c23d9011Skurt 	{}
270c23d9011Skurt };
271c23d9011Skurt 
272c23d9011Skurt /*
273c23d9011Skurt  * Used by RK809 for BUCK5
274c23d9011Skurt  *  0:		1.5V
275c23d9011Skurt  *  1-3:	1.8V-2.2V,step=200mV
276c23d9011Skurt  *  4-5:	2.8V-3.0V,step=200mV
277c23d9011Skurt  *  6-7:	3.3V-3.6V,step=300mV
278c23d9011Skurt  */
27937c734d3Snaddy const struct rkpmic_vsel_range rk809_vsel_range3[] = {
280c23d9011Skurt 	{ 1500000, 0, 0, 0 },
281c23d9011Skurt 	{ 1800000, 200000, 1, 3 },
282c23d9011Skurt 	{ 2800000, 200000, 4, 5 },
283c23d9011Skurt 	{ 3300000, 300000, 6, 7 },
284c23d9011Skurt 	{}
285c23d9011Skurt };
286c23d9011Skurt 
287c23d9011Skurt /*
288c23d9011Skurt  * Used by RK809 for LDO1-7
289c23d9011Skurt  *  0-112: 0.6V-3.4V,step=25mV
290c23d9011Skurt  */
29137c734d3Snaddy const struct rkpmic_vsel_range rk809_vsel_range4[] = {
292c23d9011Skurt 	{ 600000, 25000, 0, 112 },
293c23d9011Skurt 	{}
294c23d9011Skurt };
295c23d9011Skurt 
29637c734d3Snaddy const struct rkpmic_regdata rk809_regdata[] = {
297b8599033Skettenis 	{ "DCDC_REG1", 0xbb, 0x7f, 0xb5, 0x01, rk809_vsel_range1 },
298b8599033Skettenis 	{ "DCDC_REG2", 0xbe, 0x7f, 0xb5, 0x02, rk809_vsel_range1 },
299b8599033Skettenis 	{ "DCDC_REG3", 0xc1, 0x7f, 0xb5, 0x04, rk809_vsel_range1 },
300b8599033Skettenis 	{ "DCDC_REG4", 0xc4, 0x7f, 0xb5, 0x08, rk809_vsel_range2 },
301b8599033Skettenis 	{ "DCDC_REG5", 0xde, 0x0f, 0xb5, 0x20, rk809_vsel_range3 },
302b8599033Skettenis 	{ "LDO_REG1", 0xcc, 0x7f, 0xb6, 0x01, rk809_vsel_range4 },
303b8599033Skettenis 	{ "LDO_REG2", 0xce, 0x7f, 0xb6, 0x02, rk809_vsel_range4 },
304b8599033Skettenis 	{ "LDO_REG3", 0xd0, 0x7f, 0xb6, 0x04, rk809_vsel_range4 },
305b8599033Skettenis 	{ "LDO_REG4", 0xd2, 0x7f, 0xb6, 0x08, rk809_vsel_range4 },
306b8599033Skettenis 	{ "LDO_REG5", 0xd4, 0x7f, 0xb6, 0x10, rk809_vsel_range4 },
307b8599033Skettenis 	{ "LDO_REG6", 0xd6, 0x7f, 0xb6, 0x20, rk809_vsel_range4 },
308b8599033Skettenis 	{ "LDO_REG7", 0xd8, 0x7f, 0xb6, 0x40, rk809_vsel_range4 },
309b8599033Skettenis 	{ "LDO_REG8", 0xda, 0x7f, 0xb6, 0x80, rk809_vsel_range4 },
310b8599033Skettenis 	{ "LDO_REG9", 0xdc, 0x7f, 0xb5, 0x10, rk809_vsel_range4 },
311b8599033Skettenis 	{ "SWITCH_REG1", 0, 0, 0xb5, 0x40, NULL },
312b8599033Skettenis 	{ "SWITCH_REG2", 0, 0, 0xb5, 0x80, NULL },
31343f7f110Skettenis 	{ }
31492bce581Skettenis };
31592bce581Skettenis 
316725f2616Skettenis /*
317725f2616Skettenis  * Used by RK817 for BOOST
318725f2616Skettenis  *  0-7: 4.7V-5.4V,step=100mV
319725f2616Skettenis  */
320725f2616Skettenis const struct rkpmic_vsel_range rk817_boost_range[] = {
321725f2616Skettenis 	{ 4700000, 100000, 0, 7 },
322725f2616Skettenis 	{}
323725f2616Skettenis };
324725f2616Skettenis 
325725f2616Skettenis const struct rkpmic_regdata rk817_regdata[] = {
326b8599033Skettenis 	{ "DCDC_REG1", 0xbb, 0x7f, 0, 0, rk809_vsel_range1 },
327b8599033Skettenis 	{ "DCDC_REG2", 0xbe, 0x7f, 0, 0, rk809_vsel_range1 },
328b8599033Skettenis 	{ "DCDC_REG3", 0xc1, 0x7f, 0, 0, rk809_vsel_range1 },
329b8599033Skettenis 	{ "DCDC_REG4", 0xc4, 0x7f, 0, 0, rk809_vsel_range2 },
330b8599033Skettenis 	{ "LDO_REG1", 0xcc, 0x7f, 0, 0, rk809_vsel_range4 },
331b8599033Skettenis 	{ "LDO_REG2", 0xce, 0x7f, 0, 0, rk809_vsel_range4 },
332b8599033Skettenis 	{ "LDO_REG3", 0xd0, 0x7f, 0, 0, rk809_vsel_range4 },
333b8599033Skettenis 	{ "LDO_REG4", 0xd2, 0x7f, 0, 0, rk809_vsel_range4 },
334b8599033Skettenis 	{ "LDO_REG5", 0xd4, 0x7f, 0, 0, rk809_vsel_range4 },
335b8599033Skettenis 	{ "LDO_REG6", 0xd6, 0x7f, 0, 0, rk809_vsel_range4 },
336b8599033Skettenis 	{ "LDO_REG7", 0xd8, 0x7f, 0, 0, rk809_vsel_range4 },
337b8599033Skettenis 	{ "LDO_REG8", 0xda, 0x7f, 0, 0, rk809_vsel_range4 },
338b8599033Skettenis 	{ "LDO_REG9", 0xdc, 0x7f, 0, 0, rk809_vsel_range4 },
339b8599033Skettenis 	{ "BOOST", 0xde, 0x07, 0, 0, rk817_boost_range },
340725f2616Skettenis 	{ }
341725f2616Skettenis };
342725f2616Skettenis 
343ad688f68Skettenis struct rkpmic_softc {
344ad688f68Skettenis 	struct device sc_dev;
345ca857453Skettenis 	int sc_node;
346ca857453Skettenis 
347ca857453Skettenis 	i2c_tag_t sc_i2c_tag;
348ca857453Skettenis 	i2c_addr_t sc_i2c_addr;
349ca857453Skettenis 	spi_tag_t sc_spi_tag;
350ca857453Skettenis 	struct spi_config sc_spi_conf;
351ad688f68Skettenis 
352c23d9011Skurt 	int sc_rtc_ctrl_reg, sc_rtc_status_reg;
353*32a67d49Skettenis 	uint8_t sc_dev_ctrl_reg, sc_dev_off_val;
354*32a67d49Skettenis 
355ad688f68Skettenis 	struct todr_chip_handle sc_todr;
35637c734d3Snaddy 	const struct rkpmic_regdata *sc_regdata;
357ca857453Skettenis 
358ca857453Skettenis 	int (*sc_read)(struct rkpmic_softc *, uint8_t, void *, size_t);
359ca857453Skettenis 	int (*sc_write)(struct rkpmic_softc *, uint8_t, void *, size_t);
36030293cdcSkettenis 
36130293cdcSkettenis 	void *sc_ih;
362ad688f68Skettenis };
363ad688f68Skettenis 
364ca857453Skettenis int	rkpmic_i2c_match(struct device *, void *, void *);
365ca857453Skettenis void	rkpmic_i2c_attach(struct device *, struct device *, void *);
366ca857453Skettenis int	rkpmic_i2c_read(struct rkpmic_softc *, uint8_t, void *, size_t);
367ca857453Skettenis int	rkpmic_i2c_write(struct rkpmic_softc *, uint8_t, void *, size_t);
368ca857453Skettenis 
369ca857453Skettenis int	rkpmic_spi_match(struct device *, void *, void *);
370ca857453Skettenis void	rkpmic_spi_attach(struct device *, struct device *, void *);
371ca857453Skettenis int	rkpmic_spi_read(struct rkpmic_softc *, uint8_t, void *, size_t);
372ca857453Skettenis int	rkpmic_spi_write(struct rkpmic_softc *, uint8_t, void *, size_t);
373ca857453Skettenis 
374ad688f68Skettenis void	rkpmic_attach(struct device *, struct device *, void *);
37530293cdcSkettenis int	rkpmic_activate(struct device *, int);
376ad688f68Skettenis 
377ca857453Skettenis const struct cfattach rkpmic_i2c_ca = {
37830293cdcSkettenis 	sizeof(struct rkpmic_softc), rkpmic_i2c_match, rkpmic_i2c_attach,
37930293cdcSkettenis 	NULL, rkpmic_activate
380ca857453Skettenis };
381ca857453Skettenis 
382ca857453Skettenis const struct cfattach rkpmic_spi_ca = {
383ca857453Skettenis 	sizeof(struct rkpmic_softc), rkpmic_spi_match, rkpmic_spi_attach
384ad688f68Skettenis };
385ad688f68Skettenis 
386ad688f68Skettenis struct cfdriver rkpmic_cd = {
387ad688f68Skettenis 	NULL, "rkpmic", DV_DULL
388ad688f68Skettenis };
389ad688f68Skettenis 
39030293cdcSkettenis int	rkpmic_intr(void *);
39192bce581Skettenis void	rkpmic_attach_regulator(struct rkpmic_softc *, int);
392ad688f68Skettenis uint8_t	rkpmic_reg_read(struct rkpmic_softc *, int);
393ad688f68Skettenis void	rkpmic_reg_write(struct rkpmic_softc *, int, uint8_t);
394ad688f68Skettenis int	rkpmic_clock_read(struct rkpmic_softc *, struct clock_ymdhms *);
395ad688f68Skettenis int	rkpmic_clock_write(struct rkpmic_softc *, struct clock_ymdhms *);
396ad688f68Skettenis int	rkpmic_gettime(struct todr_chip_handle *, struct timeval *);
397ad688f68Skettenis int	rkpmic_settime(struct todr_chip_handle *, struct timeval *);
398ad688f68Skettenis 
399*32a67d49Skettenis struct rkpmic_softc *rkpmic_sc;
400*32a67d49Skettenis void    rkpmic_powerdown(void);
401*32a67d49Skettenis 
402ad688f68Skettenis int
403ca857453Skettenis rkpmic_i2c_match(struct device *parent, void *match, void *aux)
404ad688f68Skettenis {
405ad688f68Skettenis 	struct i2c_attach_args *ia = aux;
406ad688f68Skettenis 
4071ac62f4eSpatrick 	return (strcmp(ia->ia_name, "rockchip,rk805") == 0 ||
408c23d9011Skurt 	    strcmp(ia->ia_name, "rockchip,rk808") == 0 ||
409725f2616Skettenis 	    strcmp(ia->ia_name, "rockchip,rk809") == 0 ||
410725f2616Skettenis 	    strcmp(ia->ia_name, "rockchip,rk817") == 0);
411ad688f68Skettenis }
412ad688f68Skettenis 
413ad688f68Skettenis void
414ca857453Skettenis rkpmic_i2c_attach(struct device *parent, struct device *self, void *aux)
415ad688f68Skettenis {
416ad688f68Skettenis 	struct rkpmic_softc *sc = (struct rkpmic_softc *)self;
417ad688f68Skettenis 	struct i2c_attach_args *ia = aux;
418ca857453Skettenis 
419ca857453Skettenis 	sc->sc_i2c_tag = ia->ia_tag;
420ca857453Skettenis 	sc->sc_i2c_addr = ia->ia_addr;
421ca857453Skettenis 	sc->sc_node = *(int *)ia->ia_cookie;
422ca857453Skettenis 	sc->sc_read = rkpmic_i2c_read;
423ca857453Skettenis 	sc->sc_write = rkpmic_i2c_write;
424ca857453Skettenis 
425ca857453Skettenis 	rkpmic_attach(parent, self, aux);
426ca857453Skettenis }
427ca857453Skettenis 
428ca857453Skettenis int
429ca857453Skettenis rkpmic_spi_match(struct device *parent, void *match, void *aux)
430ca857453Skettenis {
431ca857453Skettenis 	struct spi_attach_args *sa = aux;
432ca857453Skettenis 
433ca857453Skettenis 	return (strcmp(sa->sa_name, "rockchip,rk806") == 0);
434ca857453Skettenis }
435ca857453Skettenis 
436ca857453Skettenis void
437ca857453Skettenis rkpmic_spi_attach(struct device *parent, struct device *self, void *aux)
438ca857453Skettenis {
439ca857453Skettenis 	struct rkpmic_softc *sc = (struct rkpmic_softc *)self;
440ca857453Skettenis 	struct spi_attach_args *sa = aux;
441ca857453Skettenis 
442ca857453Skettenis 	sc->sc_spi_tag = sa->sa_tag;
443ca857453Skettenis 	sc->sc_node = *(int *)sa->sa_cookie;
444ca857453Skettenis 	sc->sc_read = rkpmic_spi_read;
445ca857453Skettenis 	sc->sc_write = rkpmic_spi_write;
446ca857453Skettenis 
447ca857453Skettenis 	sc->sc_spi_conf.sc_bpw = 8;
448ca857453Skettenis 	sc->sc_spi_conf.sc_freq =
449ca857453Skettenis 	    OF_getpropint(sc->sc_node, "spi-max-frequency", 1000000);
450ca857453Skettenis 	sc->sc_spi_conf.sc_cs = OF_getpropint(sc->sc_node, "reg", 0);
451ca857453Skettenis 
452ca857453Skettenis 	rkpmic_attach(parent, self, aux);
453ca857453Skettenis }
454ca857453Skettenis 
455ca857453Skettenis void
456ca857453Skettenis rkpmic_attach(struct device *parent, struct device *self, void *aux)
457ca857453Skettenis {
458ca857453Skettenis 	struct rkpmic_softc *sc = (struct rkpmic_softc *)self;
45943f7f110Skettenis 	const char *chip;
46030293cdcSkettenis 	uint8_t val;
461ca857453Skettenis 	int node;
462ad688f68Skettenis 
463ca857453Skettenis 	if (OF_is_compatible(sc->sc_node, "rockchip,rk805")) {
46443f7f110Skettenis 		chip = "RK805";
465c23d9011Skurt 		sc->sc_rtc_ctrl_reg = RK805_RTC_CTRL;
466c23d9011Skurt 		sc->sc_rtc_status_reg = RK805_RTC_STATUS;
467*32a67d49Skettenis 		sc->sc_dev_ctrl_reg = RK805_DEV_CTRL;
468*32a67d49Skettenis 		sc->sc_dev_off_val = RK805_DEV_CTRL_DEV_OFF;
46943f7f110Skettenis 		sc->sc_regdata = rk805_regdata;
470ca857453Skettenis 	} else if (OF_is_compatible(sc->sc_node, "rockchip,rk806")) {
471ca857453Skettenis 		chip = "RK806";
472*32a67d49Skettenis 		sc->sc_dev_ctrl_reg = RK806_SYS_CFG3;
473*32a67d49Skettenis 		sc->sc_dev_off_val = RK806_SYS_CFG3_DEV_OFF;
474ca857453Skettenis 		sc->sc_regdata = rk806_regdata;
475ca857453Skettenis 	} else if (OF_is_compatible(sc->sc_node, "rockchip,rk808")) {
47643f7f110Skettenis 		chip = "RK808";
477c23d9011Skurt 		sc->sc_rtc_ctrl_reg = RK808_RTC_CTRL;
478c23d9011Skurt 		sc->sc_rtc_status_reg = RK808_RTC_STATUS;
479*32a67d49Skettenis 		sc->sc_dev_ctrl_reg = RK808_DEVCTRL;
480*32a67d49Skettenis 		sc->sc_dev_off_val = RK808_DEVCTRL_DEV_OFF_RST;
48143f7f110Skettenis 		sc->sc_regdata = rk808_regdata;
482ca857453Skettenis 	} else if (OF_is_compatible(sc->sc_node, "rockchip,rk809")) {
483c23d9011Skurt 		chip = "RK809";
484c23d9011Skurt 		sc->sc_rtc_ctrl_reg = RK809_RTC_CTRL;
485c23d9011Skurt 		sc->sc_rtc_status_reg = RK809_RTC_STATUS;
486*32a67d49Skettenis 		sc->sc_dev_ctrl_reg = RK809_PMIC_SYS_CFG3;
487*32a67d49Skettenis 		sc->sc_dev_off_val = RK809_PMIC_SYS_CFG3_DEV_OFF;
488c23d9011Skurt 		sc->sc_regdata = rk809_regdata;
489725f2616Skettenis 	} else {
490725f2616Skettenis 		chip = "RK817";
491725f2616Skettenis 		sc->sc_rtc_ctrl_reg = RK809_RTC_CTRL;
492725f2616Skettenis 		sc->sc_rtc_status_reg = RK809_RTC_STATUS;
493*32a67d49Skettenis 		sc->sc_dev_ctrl_reg = RK809_PMIC_SYS_CFG3;
494*32a67d49Skettenis 		sc->sc_dev_off_val = RK809_PMIC_SYS_CFG3_DEV_OFF;
495725f2616Skettenis 		sc->sc_regdata = rk817_regdata;
49643f7f110Skettenis 	}
49743f7f110Skettenis 	printf(": %s\n", chip);
49843f7f110Skettenis 
499ca857453Skettenis 	if (sc->sc_rtc_ctrl_reg) {
500ca857453Skettenis 		sc->sc_todr.cookie = sc;
501ca857453Skettenis 		sc->sc_todr.todr_gettime = rkpmic_gettime;
502ca857453Skettenis 		sc->sc_todr.todr_settime = rkpmic_settime;
503ca857453Skettenis 		sc->sc_todr.todr_quality = 0;
504ca857453Skettenis 		todr_attach(&sc->sc_todr);
505ca857453Skettenis 	}
506ca857453Skettenis 
507ca857453Skettenis 	node = OF_getnodebyname(sc->sc_node, "regulators");
50892bce581Skettenis 	if (node == 0)
50992bce581Skettenis 		return;
51092bce581Skettenis 	for (node = OF_child(node); node; node = OF_peer(node))
51192bce581Skettenis 		rkpmic_attach_regulator(sc, node);
51230293cdcSkettenis 
51330293cdcSkettenis 	if (OF_is_compatible(sc->sc_node, "rockchip,rk809")) {
51430293cdcSkettenis 		/* Mask all interrupts. */
51530293cdcSkettenis 		rkpmic_reg_write(sc, RK809_PMIC_INT_MSK0, 0xff);
51630293cdcSkettenis 		rkpmic_reg_write(sc, RK809_PMIC_INT_MSK1, 0xff);
51730293cdcSkettenis 		rkpmic_reg_write(sc, RK809_PMIC_INT_MSK2, 0xff);
51830293cdcSkettenis 
51930293cdcSkettenis 		/* Ack all interrupts. */
52030293cdcSkettenis 		rkpmic_reg_write(sc, RK809_PMIC_INT_STS0, 0xff);
52130293cdcSkettenis 		rkpmic_reg_write(sc, RK809_PMIC_INT_STS1, 0xff);
52230293cdcSkettenis 		rkpmic_reg_write(sc, RK809_PMIC_INT_STS2, 0xff);
52330293cdcSkettenis 
52430293cdcSkettenis 		/* Set interrupt pin to active-low. */
52530293cdcSkettenis 		val = rkpmic_reg_read(sc, RK809_PMIC_GPIO_INT_CONFIG);
52630293cdcSkettenis 		rkpmic_reg_write(sc, RK809_PMIC_GPIO_INT_CONFIG,
52730293cdcSkettenis 		    val & ~RK809_PMIC_GPIO_INT_CONFIG_INT_POL);
52830293cdcSkettenis 
52930293cdcSkettenis 		sc->sc_ih = fdt_intr_establish(sc->sc_node, IPL_TTY,
53030293cdcSkettenis 		    rkpmic_intr, sc, sc->sc_dev.dv_xname);
53130293cdcSkettenis 
53230293cdcSkettenis 		/* Unmask power button interrupt. */
53330293cdcSkettenis 		rkpmic_reg_write(sc, RK809_PMIC_INT_MSK0,
53430293cdcSkettenis 		    ~RK809_PMIC_INT_MSK0_PWRON_FALL_INT_IM);
53530293cdcSkettenis 
53630293cdcSkettenis #ifdef SUSPEND
53730293cdcSkettenis 		if (OF_getpropbool(sc->sc_node, "wakeup-source"))
53830293cdcSkettenis 			device_register_wakeup(&sc->sc_dev);
53930293cdcSkettenis #endif
54030293cdcSkettenis 	}
541*32a67d49Skettenis 
542*32a67d49Skettenis 	if (OF_getpropbool(sc->sc_node, "system-power-controller") ||
543*32a67d49Skettenis 	    OF_getpropbool(sc->sc_node, "rockchip,system-power-controller")) {
544*32a67d49Skettenis 		rkpmic_sc = sc;
545*32a67d49Skettenis 		powerdownfn = rkpmic_powerdown;
546*32a67d49Skettenis 	}
54730293cdcSkettenis }
54830293cdcSkettenis 
54930293cdcSkettenis int
55030293cdcSkettenis rkpmic_activate(struct device *self, int act)
55130293cdcSkettenis {
55230293cdcSkettenis 	struct rkpmic_softc *sc = (struct rkpmic_softc *)self;
55330293cdcSkettenis 	uint8_t val;
55430293cdcSkettenis 
55530293cdcSkettenis 	switch (act) {
55630293cdcSkettenis 	case DVACT_SUSPEND:
55730293cdcSkettenis 		if (OF_is_compatible(sc->sc_node, "rockchip,rk809")) {
55830293cdcSkettenis 			val = rkpmic_reg_read(sc, RK809_PMIC_SYS_CFG3);
55930293cdcSkettenis 			val &= ~RK809_PMIC_SYS_CFG3_SLP_FUN_MASK;
56030293cdcSkettenis 			val |= RK809_PMIC_SYS_CFG3_SLP_FUN_SLEEP;
56130293cdcSkettenis 			rkpmic_reg_write(sc, RK809_PMIC_SYS_CFG3, val);
56230293cdcSkettenis 		}
56330293cdcSkettenis 		break;
56430293cdcSkettenis 	case DVACT_RESUME:
56530293cdcSkettenis 		if (OF_is_compatible(sc->sc_node, "rockchip,rk809")) {
56630293cdcSkettenis 			val = rkpmic_reg_read(sc, RK809_PMIC_SYS_CFG3);
56730293cdcSkettenis 			val &= ~RK809_PMIC_SYS_CFG3_SLP_FUN_MASK;
56830293cdcSkettenis 			val |= RK809_PMIC_SYS_CFG3_SLP_FUN_NONE;
56930293cdcSkettenis 			rkpmic_reg_write(sc, RK809_PMIC_SYS_CFG3, val);
570456d6666Skettenis 			rkpmic_reg_write(sc, RK809_PMIC_INT_STS0, 0xff);
57130293cdcSkettenis 		}
57230293cdcSkettenis 		break;
57330293cdcSkettenis 	}
57430293cdcSkettenis 
57530293cdcSkettenis 	return 0;
57630293cdcSkettenis }
57730293cdcSkettenis 
57830293cdcSkettenis int
57930293cdcSkettenis rkpmic_intr(void *arg)
58030293cdcSkettenis {
58130293cdcSkettenis 	extern int allowpowerdown;
58230293cdcSkettenis 	struct rkpmic_softc *sc = arg;
58330293cdcSkettenis 
58430293cdcSkettenis 	if (allowpowerdown) {
58530293cdcSkettenis 		allowpowerdown = 0;
58630293cdcSkettenis 		prsignal(initprocess, SIGUSR2);
58730293cdcSkettenis 	}
58830293cdcSkettenis 
58930293cdcSkettenis 	rkpmic_reg_write(sc, RK809_PMIC_INT_STS0, 0xff);
59030293cdcSkettenis 	return 1;
59192bce581Skettenis }
59292bce581Skettenis 
593*32a67d49Skettenis void
594*32a67d49Skettenis rkpmic_powerdown(void)
595*32a67d49Skettenis {
596*32a67d49Skettenis 	struct rkpmic_softc *sc = rkpmic_sc;
597*32a67d49Skettenis 	rkpmic_reg_write(sc, sc->sc_dev_ctrl_reg,
598*32a67d49Skettenis 	    rkpmic_reg_read(sc, sc->sc_dev_ctrl_reg) | sc->sc_dev_off_val);
599*32a67d49Skettenis }
600*32a67d49Skettenis 
60192bce581Skettenis struct rkpmic_regulator {
60292bce581Skettenis 	struct rkpmic_softc *rr_sc;
60392bce581Skettenis 
604b8599033Skettenis 	uint8_t rr_vreg, rr_vmask;
60537c734d3Snaddy 	const struct rkpmic_vsel_range *rr_vsel_range;
60692bce581Skettenis 
60792bce581Skettenis 	struct regulator_device rr_rd;
60892bce581Skettenis };
60992bce581Skettenis 
61092bce581Skettenis uint32_t rkpmic_get_voltage(void *);
611db6014e5Skettenis int	rkpmic_set_voltage(void *, uint32_t);
612b8599033Skettenis int	rkpmic_do_set_voltage(struct rkpmic_regulator *, uint32_t, int);
61392bce581Skettenis 
61492bce581Skettenis void
61592bce581Skettenis rkpmic_attach_regulator(struct rkpmic_softc *sc, int node)
61692bce581Skettenis {
61792bce581Skettenis 	struct rkpmic_regulator *rr;
61892bce581Skettenis 	char name[32];
619b8599033Skettenis 	uint32_t voltage;
620b8599033Skettenis 	int i, snode;
621b8599033Skettenis 	uint8_t val;
62292bce581Skettenis 
62392bce581Skettenis 	name[0] = 0;
62492bce581Skettenis 	OF_getprop(node, "name", name, sizeof(name));
62592bce581Skettenis 	name[sizeof(name) - 1] = 0;
62643f7f110Skettenis 	for (i = 0; sc->sc_regdata[i].name; i++) {
62743f7f110Skettenis 		if (strcmp(sc->sc_regdata[i].name, name) == 0)
62892bce581Skettenis 			break;
62992bce581Skettenis 	}
63043f7f110Skettenis 	if (sc->sc_regdata[i].name == NULL)
63192bce581Skettenis 		return;
63292bce581Skettenis 
63392bce581Skettenis 	rr = malloc(sizeof(*rr), M_DEVBUF, M_WAITOK | M_ZERO);
63492bce581Skettenis 	rr->rr_sc = sc;
63592bce581Skettenis 
636b8599033Skettenis 	rr->rr_vreg = sc->sc_regdata[i].vreg;
637b8599033Skettenis 	rr->rr_vmask = sc->sc_regdata[i].vmask;
638c23d9011Skurt 	rr->rr_vsel_range = sc->sc_regdata[i].vsel_range;
63992bce581Skettenis 
64092bce581Skettenis 	rr->rr_rd.rd_node = node;
64192bce581Skettenis 	rr->rr_rd.rd_cookie = rr;
64292bce581Skettenis 	rr->rr_rd.rd_get_voltage = rkpmic_get_voltage;
643db6014e5Skettenis 	rr->rr_rd.rd_set_voltage = rkpmic_set_voltage;
64492bce581Skettenis 	regulator_register(&rr->rr_rd);
645b8599033Skettenis 
646b8599033Skettenis 	if (sc->sc_regdata[i].smask) {
647b8599033Skettenis 		snode = OF_getnodebyname(node, "regulator-state-mem");
648b8599033Skettenis 		if (snode) {
649b8599033Skettenis 			val = rkpmic_reg_read(sc, sc->sc_regdata[i].sreg);
650b8599033Skettenis 			if (OF_getpropbool(snode, "regulator-on-in-suspend"))
651b8599033Skettenis 				val |= sc->sc_regdata[i].smask;
652b8599033Skettenis 			if (OF_getpropbool(snode, "regulator-off-in-suspend"))
653b8599033Skettenis 				val &= ~sc->sc_regdata[i].smask;
654b8599033Skettenis 			rkpmic_reg_write(sc, sc->sc_regdata[i].sreg, val);
655b8599033Skettenis 
656b8599033Skettenis 			voltage = OF_getpropint(snode,
657b8599033Skettenis 			    "regulator-suspend-min-microvolt", 0);
658b8599033Skettenis 			voltage = OF_getpropint(snode,
659b8599033Skettenis 			    "regulator-suspend-microvolt", voltage);
660b8599033Skettenis 			if (voltage > 0)
661b8599033Skettenis 				rkpmic_do_set_voltage(rr, voltage, 1);
662b8599033Skettenis 		}
663b8599033Skettenis 	}
66492bce581Skettenis }
66592bce581Skettenis 
66692bce581Skettenis uint32_t
66792bce581Skettenis rkpmic_get_voltage(void *cookie)
66892bce581Skettenis {
66992bce581Skettenis 	struct rkpmic_regulator *rr = cookie;
67037c734d3Snaddy 	const struct rkpmic_vsel_range *vsel_range = rr->rr_vsel_range;
671db6014e5Skettenis 	uint8_t vsel;
672c23d9011Skurt 	uint32_t ret = 0;
67392bce581Skettenis 
674b8599033Skettenis 	if (vsel_range == NULL)
675b8599033Skettenis 		return 0;
676b8599033Skettenis 
677b8599033Skettenis 	vsel = rkpmic_reg_read(rr->rr_sc, rr->rr_vreg) & rr->rr_vmask;
678c23d9011Skurt 
679c23d9011Skurt 	while (vsel_range->base) {
680c23d9011Skurt 		ret = vsel_range->base;
681c23d9011Skurt 		if (vsel >= vsel_range->vsel_min &&
682c23d9011Skurt 		    vsel <= vsel_range->vsel_max) {
683c23d9011Skurt 			ret += (vsel - vsel_range->vsel_min) *
684c23d9011Skurt 			    vsel_range->delta;
685c23d9011Skurt 			break;
686c23d9011Skurt 		} else
687c23d9011Skurt 			ret += (vsel_range->vsel_max - vsel_range->vsel_min) *
688c23d9011Skurt 			    vsel_range->delta;
689c23d9011Skurt 		vsel_range++;
690c23d9011Skurt 
691c23d9011Skurt 	}
692c23d9011Skurt 
693c23d9011Skurt 	return ret;
694db6014e5Skettenis }
695db6014e5Skettenis 
696db6014e5Skettenis int
697db6014e5Skettenis rkpmic_set_voltage(void *cookie, uint32_t voltage)
698db6014e5Skettenis {
699b8599033Skettenis 	return rkpmic_do_set_voltage(cookie, voltage, 0);
700b8599033Skettenis }
701b8599033Skettenis 
702b8599033Skettenis int
703b8599033Skettenis rkpmic_do_set_voltage(struct rkpmic_regulator *rr, uint32_t voltage, int sleep)
704b8599033Skettenis {
70537c734d3Snaddy 	const struct rkpmic_vsel_range *vsel_range = rr->rr_vsel_range;
706c23d9011Skurt 	uint32_t vmin, vmax, volt;
707c23d9011Skurt 	uint8_t reg, vsel;
708db6014e5Skettenis 
709b8599033Skettenis 	if (vsel_range == NULL)
710b8599033Skettenis 		return ENODEV;
711b8599033Skettenis 
712c23d9011Skurt 	while (vsel_range->base) {
713c23d9011Skurt 		vmin = vsel_range->base;
714c23d9011Skurt 		vmax = vmin + (vsel_range->vsel_max - vsel_range->vsel_min) *
715c23d9011Skurt 		    vsel_range->delta;
716c23d9011Skurt 		if (voltage < vmin)
717c23d9011Skurt 			return EINVAL;
718c23d9011Skurt 		if (voltage <= vmax) {
719c23d9011Skurt 			vsel = vsel_range->vsel_min;
720c23d9011Skurt 			volt = vsel_range->base;
721c23d9011Skurt 			while (vsel <= vsel_range->vsel_max) {
722c23d9011Skurt 				if (volt == voltage)
723c23d9011Skurt 					break;
724c23d9011Skurt 				else {
725c23d9011Skurt 					vsel++;
726c23d9011Skurt 					volt += vsel_range->delta;
727c23d9011Skurt 				}
728c23d9011Skurt 			}
729c23d9011Skurt 			if (volt != voltage)
730c23d9011Skurt 				return EINVAL;
731c23d9011Skurt 			break;
732c23d9011Skurt 		}
733c23d9011Skurt 		vsel_range++;
734c23d9011Skurt 	}
735c23d9011Skurt 
736c23d9011Skurt 	if (vsel_range->base == 0)
737db6014e5Skettenis 		return EINVAL;
738db6014e5Skettenis 
739b8599033Skettenis 	reg = rkpmic_reg_read(rr->rr_sc, rr->rr_vreg + sleep);
740b8599033Skettenis 	reg &= ~rr->rr_vmask;
741c23d9011Skurt 	reg |= vsel;
742b8599033Skettenis 	rkpmic_reg_write(rr->rr_sc, rr->rr_vreg + sleep, reg);
743db6014e5Skettenis 
744db6014e5Skettenis 	return 0;
745ad688f68Skettenis }
746ad688f68Skettenis 
747ad688f68Skettenis int
748ad688f68Skettenis rkpmic_gettime(struct todr_chip_handle *handle, struct timeval *tv)
749ad688f68Skettenis {
750ad688f68Skettenis 	struct rkpmic_softc *sc = handle->cookie;
751ad688f68Skettenis 	struct clock_ymdhms dt;
752ad688f68Skettenis 	time_t secs;
753ad688f68Skettenis 	int error;
754ad688f68Skettenis 
755ad688f68Skettenis 	error = rkpmic_clock_read(sc, &dt);
756ad688f68Skettenis 	if (error)
757ad688f68Skettenis 		return error;
758ad688f68Skettenis 
759ad688f68Skettenis 	if (dt.dt_sec > 59 || dt.dt_min > 59 || dt.dt_hour > 23 ||
760ad688f68Skettenis 	    dt.dt_day > 31 || dt.dt_day == 0 ||
761ad688f68Skettenis 	    dt.dt_mon > 12 || dt.dt_mon == 0 ||
762ad688f68Skettenis 	    dt.dt_year < POSIX_BASE_YEAR)
763ad688f68Skettenis 		return EINVAL;
764ad688f68Skettenis 
765ad688f68Skettenis 	/*
766ad688f68Skettenis 	 * The RTC thinks November has 31 days.  Match what Linux does
7679bec9e43Sjsg 	 * and undo the damage by considering the calendars to be in
768ad688f68Skettenis 	 * sync on January 1st 2016.
769ad688f68Skettenis 	 */
770ad688f68Skettenis 	secs = clock_ymdhms_to_secs(&dt);
771ad688f68Skettenis 	secs += (dt.dt_year - 2016 + (dt.dt_mon == 12 ? 1 : 0)) * 86400;
772ad688f68Skettenis 
773ad688f68Skettenis 	tv->tv_sec = secs;
774ad688f68Skettenis 	tv->tv_usec = 0;
775ad688f68Skettenis 	return 0;
776ad688f68Skettenis }
777ad688f68Skettenis 
778ad688f68Skettenis int
779ad688f68Skettenis rkpmic_settime(struct todr_chip_handle *handle, struct timeval *tv)
780ad688f68Skettenis {
781ad688f68Skettenis 	struct rkpmic_softc *sc = handle->cookie;
782ad688f68Skettenis 	struct clock_ymdhms dt;
783ad688f68Skettenis 	time_t secs;
784ad688f68Skettenis 
785ad688f68Skettenis 	/*
78610770a61Sjasper 	 * Take care of the November 31st braindamage here as well.
787ad688f68Skettenis 	 * Don't try to be clever, just do the conversion in two
788ad688f68Skettenis 	 * steps, first taking care of November 31 in previous years,
789ad688f68Skettenis 	 * and then taking care of days in December of the current
7909bec9e43Sjsg 	 * year.  December 1st turns into November 31st!
791ad688f68Skettenis 	 */
792ad688f68Skettenis 	secs = tv->tv_sec;
793ad688f68Skettenis 	clock_secs_to_ymdhms(secs, &dt);
794ad688f68Skettenis 	secs -= (dt.dt_year - 2016) * 86400;
795ad688f68Skettenis 	clock_secs_to_ymdhms(secs, &dt);
796ad688f68Skettenis 	if (dt.dt_mon == 12) {
797ad688f68Skettenis 		dt.dt_day--;
798ad688f68Skettenis 		if (dt.dt_day == 0) {
799ad688f68Skettenis 			dt.dt_mon = 11;
800ad688f68Skettenis 			dt.dt_day = 31;
801ad688f68Skettenis 		}
802ad688f68Skettenis 	}
803ad688f68Skettenis 
804ad688f68Skettenis 	return rkpmic_clock_write(sc, &dt);
805ad688f68Skettenis }
806ad688f68Skettenis 
807ad688f68Skettenis uint8_t
808ad688f68Skettenis rkpmic_reg_read(struct rkpmic_softc *sc, int reg)
809ad688f68Skettenis {
810ad688f68Skettenis 	uint8_t cmd = reg;
811ad688f68Skettenis 	uint8_t val;
812ad688f68Skettenis 
813ca857453Skettenis 	if (sc->sc_read(sc, cmd, &val, sizeof(val))) {
814ad688f68Skettenis 		printf("%s: can't read register 0x%02x\n",
815ad688f68Skettenis 		    sc->sc_dev.dv_xname, reg);
816ad688f68Skettenis 		val = 0xff;
817ad688f68Skettenis 	}
818ad688f68Skettenis 
819ad688f68Skettenis 	return val;
820ad688f68Skettenis }
821ad688f68Skettenis 
822ad688f68Skettenis void
823ad688f68Skettenis rkpmic_reg_write(struct rkpmic_softc *sc, int reg, uint8_t val)
824ad688f68Skettenis {
825ad688f68Skettenis 	uint8_t cmd = reg;
826ad688f68Skettenis 
827ca857453Skettenis 	if (sc->sc_write(sc, cmd, &val, sizeof(val))) {
828ad688f68Skettenis 		printf("%s: can't write register 0x%02x\n",
829ad688f68Skettenis 		    sc->sc_dev.dv_xname, reg);
830ad688f68Skettenis 	}
831ad688f68Skettenis }
832ad688f68Skettenis 
833ad688f68Skettenis int
834ad688f68Skettenis rkpmic_clock_read(struct rkpmic_softc *sc, struct clock_ymdhms *dt)
835ad688f68Skettenis {
836c23d9011Skurt 	uint8_t regs[RK80X_NRTC_REGS];
837c23d9011Skurt 	uint8_t cmd = RK80X_SECONDS;
838ad688f68Skettenis 	uint8_t status;
839ad688f68Skettenis 	int error;
840ad688f68Skettenis 
841ca857453Skettenis 	error = sc->sc_read(sc, cmd, regs, RK80X_NRTC_REGS);
842ad688f68Skettenis 
843ad688f68Skettenis 	if (error) {
844ad688f68Skettenis 		printf("%s: can't read RTC\n", sc->sc_dev.dv_xname);
845ad688f68Skettenis 		return error;
846ad688f68Skettenis 	}
847ad688f68Skettenis 
848ad688f68Skettenis 	/*
849c23d9011Skurt 	 * Convert the RK80x's register values into something useable.
850ad688f68Skettenis 	 */
851ad688f68Skettenis 	dt->dt_sec = FROMBCD(regs[0]);
852ad688f68Skettenis 	dt->dt_min = FROMBCD(regs[1]);
853ad688f68Skettenis 	dt->dt_hour = FROMBCD(regs[2]);
854ad688f68Skettenis 	dt->dt_day = FROMBCD(regs[3]);
855ad688f68Skettenis 	dt->dt_mon = FROMBCD(regs[4]);
856ad688f68Skettenis 	dt->dt_year = FROMBCD(regs[5]) + 2000;
857ad688f68Skettenis 
858ad688f68Skettenis 	/* Consider the time to be invalid if the POWER_UP bit is set. */
859c23d9011Skurt 	status = rkpmic_reg_read(sc, sc->sc_rtc_status_reg);
860c23d9011Skurt 	if (status & RK80X_RTC_STATUS_POWER_UP)
861ad688f68Skettenis 		return EINVAL;
862ad688f68Skettenis 
863ad688f68Skettenis 	return 0;
864ad688f68Skettenis }
865ad688f68Skettenis 
866ad688f68Skettenis int
867ad688f68Skettenis rkpmic_clock_write(struct rkpmic_softc *sc, struct clock_ymdhms *dt)
868ad688f68Skettenis {
869c23d9011Skurt 	uint8_t regs[RK80X_NRTC_REGS];
870c23d9011Skurt 	uint8_t cmd = RK80X_SECONDS;
871ad688f68Skettenis 	int error;
872ad688f68Skettenis 
873ad688f68Skettenis 	/*
874c23d9011Skurt 	 * Convert our time representation into something the RK80x
875ad688f68Skettenis 	 * can understand.
876ad688f68Skettenis 	 */
877ad688f68Skettenis 	regs[0] = TOBCD(dt->dt_sec);
878ad688f68Skettenis 	regs[1] = TOBCD(dt->dt_min);
879ad688f68Skettenis 	regs[2] = TOBCD(dt->dt_hour);
880ad688f68Skettenis 	regs[3] = TOBCD(dt->dt_day);
881ad688f68Skettenis 	regs[4] = TOBCD(dt->dt_mon);
882ad688f68Skettenis 	regs[5] = TOBCD(dt->dt_year - 2000);
883ad688f68Skettenis 	regs[6] = TOBCD(dt->dt_wday);
884ad688f68Skettenis 
885ad688f68Skettenis 	/* Stop RTC such that we can write to it. */
886c23d9011Skurt 	rkpmic_reg_write(sc, sc->sc_rtc_ctrl_reg, RK80X_RTC_CTRL_STOP_RTC);
887ad688f68Skettenis 
888ca857453Skettenis 	error = sc->sc_write(sc, cmd, regs, RK80X_NRTC_REGS);
889ad688f68Skettenis 
890ad688f68Skettenis 	/* Restart RTC. */
891c23d9011Skurt 	rkpmic_reg_write(sc, sc->sc_rtc_ctrl_reg, 0);
892ad688f68Skettenis 
893ad688f68Skettenis 	if (error) {
894ad688f68Skettenis 		printf("%s: can't write RTC\n", sc->sc_dev.dv_xname);
895ad688f68Skettenis 		return error;
896ad688f68Skettenis 	}
897ad688f68Skettenis 
898ad688f68Skettenis 	/* Clear POWER_UP bit to indicate the time is now valid. */
899c23d9011Skurt 	rkpmic_reg_write(sc, sc->sc_rtc_status_reg, RK80X_RTC_STATUS_POWER_UP);
900ad688f68Skettenis 
901ad688f68Skettenis 	return 0;
902ad688f68Skettenis }
903ca857453Skettenis 
904ca857453Skettenis int
905ca857453Skettenis rkpmic_i2c_read(struct rkpmic_softc *sc, uint8_t cmd, void *buf, size_t buflen)
906ca857453Skettenis {
907ca857453Skettenis 	int error;
908ca857453Skettenis 
909ca857453Skettenis 	iic_acquire_bus(sc->sc_i2c_tag, I2C_F_POLL);
910ca857453Skettenis 	error = iic_exec(sc->sc_i2c_tag, I2C_OP_READ_WITH_STOP,
911ca857453Skettenis 	    sc->sc_i2c_addr, &cmd, sizeof(cmd), buf, buflen, I2C_F_POLL);
912ca857453Skettenis 	iic_release_bus(sc->sc_i2c_tag, I2C_F_POLL);
913ca857453Skettenis 
914ca857453Skettenis 	return error;
915ca857453Skettenis }
916ca857453Skettenis 
917ca857453Skettenis int
918ca857453Skettenis rkpmic_i2c_write(struct rkpmic_softc *sc, uint8_t cmd, void *buf, size_t buflen)
919ca857453Skettenis {
920ca857453Skettenis 	int error;
921ca857453Skettenis 
922ca857453Skettenis 	iic_acquire_bus(sc->sc_i2c_tag, I2C_F_POLL);
923ca857453Skettenis 	error = iic_exec(sc->sc_i2c_tag, I2C_OP_WRITE_WITH_STOP,
924ca857453Skettenis 	    sc->sc_i2c_addr, &cmd, sizeof(cmd), buf, buflen, I2C_F_POLL);
925ca857453Skettenis 	iic_release_bus(sc->sc_i2c_tag, I2C_F_POLL);
926ca857453Skettenis 
927ca857453Skettenis 	return error;
928ca857453Skettenis }
929ca857453Skettenis 
930ca857453Skettenis int
931ca857453Skettenis rkpmic_spi_read(struct rkpmic_softc *sc, uint8_t cmd, void *buf, size_t buflen)
932ca857453Skettenis {
933ca857453Skettenis 	uint8_t cmdbuf[3];
934ca857453Skettenis 	int error;
935ca857453Skettenis 
936ca857453Skettenis 	cmdbuf[0] = RKSPI_CMD_READ | (buflen - 1);
937ca857453Skettenis 	cmdbuf[1] = cmd;  /* 16-bit addr low */
938ca857453Skettenis 	cmdbuf[2] = 0x00; /* 16-bit addr high */
939ca857453Skettenis 
940ca857453Skettenis 	spi_acquire_bus(sc->sc_spi_tag, 0);
941ca857453Skettenis 	spi_config(sc->sc_spi_tag, &sc->sc_spi_conf);
942ca857453Skettenis 	error = spi_transfer(sc->sc_spi_tag, cmdbuf, NULL, sizeof(cmdbuf),
943ca857453Skettenis 	    SPI_KEEP_CS);
944ca857453Skettenis 	if (!error)
945ca857453Skettenis 		error = spi_read(sc->sc_spi_tag, buf, buflen);
946ca857453Skettenis 	spi_release_bus(sc->sc_spi_tag, 0);
947ca857453Skettenis 
948ca857453Skettenis 	return error;
949ca857453Skettenis }
950ca857453Skettenis 
951ca857453Skettenis int
952ca857453Skettenis rkpmic_spi_write(struct rkpmic_softc *sc, uint8_t cmd, void *buf, size_t buflen)
953ca857453Skettenis {
954ca857453Skettenis 	uint8_t cmdbuf[3];
955ca857453Skettenis 	int error;
956ca857453Skettenis 
957ca857453Skettenis 	cmdbuf[0] = RKSPI_CMD_WRITE | (buflen - 1);
958ca857453Skettenis 	cmdbuf[1] = cmd;  /* 16-bit addr low */
959ca857453Skettenis 	cmdbuf[2] = 0x00; /* 16-bit addr high */
960ca857453Skettenis 
961ca857453Skettenis 	spi_acquire_bus(sc->sc_spi_tag, 0);
962ca857453Skettenis 	spi_config(sc->sc_spi_tag, &sc->sc_spi_conf);
963ca857453Skettenis 	error = spi_transfer(sc->sc_spi_tag, cmdbuf, NULL, sizeof(cmdbuf),
964ca857453Skettenis 	    SPI_KEEP_CS);
965ca857453Skettenis 	if (!error)
966ca857453Skettenis 		error = spi_write(sc->sc_spi_tag, buf, buflen);
967ca857453Skettenis 	spi_release_bus(sc->sc_spi_tag, 0);
968ca857453Skettenis 
969ca857453Skettenis 	return error;
970ca857453Skettenis }
971