xref: /openbsd-src/sys/dev/fdt/axppmic.c (revision 3b536516568d1fa843101e793ba51ad941c102d7)
1*3b536516Sjsg /*	$OpenBSD: axppmic.c,v 1.21 2024/10/06 03:46:48 jsg Exp $	*/
2b393861dSkettenis /*
3b393861dSkettenis  * Copyright (c) 2017 Mark Kettenis <kettenis@openbsd.org>
4b393861dSkettenis  *
5b393861dSkettenis  * Permission to use, copy, modify, and distribute this software for any
6b393861dSkettenis  * purpose with or without fee is hereby granted, provided that the above
7b393861dSkettenis  * copyright notice and this permission notice appear in all copies.
8b393861dSkettenis  *
9b393861dSkettenis  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10b393861dSkettenis  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11b393861dSkettenis  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12b393861dSkettenis  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13b393861dSkettenis  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14b393861dSkettenis  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15b393861dSkettenis  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16b393861dSkettenis  */
17b393861dSkettenis 
18b393861dSkettenis #include <sys/param.h>
19b393861dSkettenis #include <sys/systm.h>
20b393861dSkettenis #include <sys/device.h>
21b393861dSkettenis #include <sys/malloc.h>
22de7daf7eSkettenis #include <sys/sensors.h>
23b393861dSkettenis 
24de7daf7eSkettenis #include <dev/i2c/i2cvar.h>
25b393861dSkettenis #include <dev/fdt/rsbvar.h>
26b393861dSkettenis 
27b393861dSkettenis #include <dev/ofw/openfirm.h>
28b393861dSkettenis #include <dev/ofw/ofw_regulator.h>
29b393861dSkettenis #include <dev/ofw/fdt.h>
30b393861dSkettenis 
31de7daf7eSkettenis extern void (*powerdownfn)(void);
32de7daf7eSkettenis 
33de7daf7eSkettenis #define AXP209_SDR		0x32
34de7daf7eSkettenis #define  AXP209_SDR_SHUTDOWN	(1 << 7)
35de7daf7eSkettenis #define AXP209_ADC_EN1		0x82
36de7daf7eSkettenis #define  AXP209_ADC_EN1_ACIN	(3 << 4)
37de7daf7eSkettenis #define  AXP209_ADC_EN1_VBUS	(3 << 2)
38de7daf7eSkettenis 
397a19eddcSkettenis #define AXP803_IRQ1_EN		0x40
407a19eddcSkettenis #define AXP803_IRQ2_EN		0x41
417a19eddcSkettenis #define AXP803_IRQ3_EN		0x42
427a19eddcSkettenis #define AXP803_IRQ4_EN		0x43
437a19eddcSkettenis #define AXP803_IRQ5_EN		0x44
447a19eddcSkettenis #define  AXP803_IRQ5_EN_PEK_SHORT	(1 << 4)
457a19eddcSkettenis #define AXP803_IRQ6_EN		0x45
467a19eddcSkettenis #define AXP803_IRQ1_STAT	0x48
477a19eddcSkettenis #define AXP803_IRQ2_STAT	0x49
487a19eddcSkettenis #define AXP803_IRQ3_STAT	0x4a
497a19eddcSkettenis #define AXP803_IRQ4_STAT	0x4b
507a19eddcSkettenis #define AXP803_IRQ5_STAT	0x4c
517a19eddcSkettenis #define  AXP803_IRQ5_STAT_PEK_SHORT	(1 << 4)
527a19eddcSkettenis #define AXP803_IRQ6_STAT	0x4d
53e6b4a485Skettenis #define AXP803_BAT_CAP_WARN		0xe6
54e6b4a485Skettenis #define  AXP803_BAT_CAP_WARN_LV1	0xf0
55e6b4a485Skettenis #define  AXP803_BAT_CAP_WARN_LV1BASE	5
56e6b4a485Skettenis #define  AXP803_BAT_CAP_WARN_LV2	0x0f
57e6b4a485Skettenis 
58b393861dSkettenis #define AXP806_REG_ADDR_EXT			0xff
59b393861dSkettenis #define  AXP806_REG_ADDR_EXT_MASTER_MODE	(0 << 4)
60b393861dSkettenis #define  AXP806_REG_ADDR_EXT_SLAVE_MODE		(1 << 4)
61b393861dSkettenis 
62bad8128fSkettenis /* Regulators for AXP209, AXP221, AXP806 and AXP809. */
63de7daf7eSkettenis 
64b393861dSkettenis struct axppmic_regdata {
65b393861dSkettenis 	const char *name;
66b393861dSkettenis 	uint8_t ereg, emask, eval, dval;
67b393861dSkettenis 	uint8_t vreg, vmask;
68ae0af167Suaa 	uint32_t base, delta, nsteps;
69ae0af167Suaa 	uint32_t base2, delta2, nsteps2;
70b393861dSkettenis };
71b393861dSkettenis 
7237c734d3Snaddy const struct axppmic_regdata axp209_regdata[] = {
73de7daf7eSkettenis 	{ "dcdc2", 0x12, (1 << 4), (1 << 4), (0 << 4),
74ae0af167Suaa 	  0x23, 0x3f, 700000, 25000, 64 },
75de7daf7eSkettenis 	{ "dcdc3", 0x12, (1 << 1), (1 << 1), (0 << 1),
76ae0af167Suaa 	  0x27, 0x7f, 700000, 25000, 113 },
77de7daf7eSkettenis 	/* LDO1 can't be controlled */
78de7daf7eSkettenis 	{ "ldo2", 0x12, (1 << 2), (1 << 2), (0 << 2),
79ae0af167Suaa 	  0x28, 0xf0, 1800000, (100000 >> 4), (16 << 4) },
80de7daf7eSkettenis 	{ "ldo3", 0x12, (1 << 6), (1 << 6), (0 << 6),
81ae0af167Suaa 	  0x29, 0x7f, 700000, 25000, 113 },
82de7daf7eSkettenis 	/* LDO4 voltage levels are complicated */
83de7daf7eSkettenis 	{ "ldo5", 0x90, 0x07, 0x03, 0x07,
84ae0af167Suaa 	  0x91, 0xf0, 1800000, (100000 >> 4), (16 << 4) },
85de7daf7eSkettenis 	{ NULL }
86de7daf7eSkettenis };
87de7daf7eSkettenis 
8837c734d3Snaddy const struct axppmic_regdata axp221_regdata[] = {
89bad8128fSkettenis 	{ "dcdc1", 0x10, (1 << 1), (1 << 1), (0 << 1),
90ae0af167Suaa 	  0x21, 0x1f, 1600000, 100000, 19 },
91bad8128fSkettenis 	{ "dcdc2", 0x10, (1 << 2), (1 << 2), (0 << 2),
92ae0af167Suaa 	  0x22, 0x3f, 600000, 20000, 48 },
93bad8128fSkettenis 	{ "dcdc3", 0x10, (1 << 3), (1 << 3), (0 << 3),
94ae0af167Suaa 	  0x23, 0x3f, 600000, 20000, 64 },
95bad8128fSkettenis 	{ "dcdc4", 0x10, (1 << 4), (1 << 4), (0 << 4),
96ae0af167Suaa 	  0x24, 0x3f, 600000, 20000, 48 },
97bad8128fSkettenis 	{ "dcdc5", 0x10, (1 << 5), (1 << 5), (0 << 5),
98ae0af167Suaa 	  0x25, 0x1f, 1000000, 50000, 32 },
99bad8128fSkettenis 	{ "dc1sw", 0x12, (1 << 7), (1 << 7), (0 << 7) },
100bad8128fSkettenis 	{ "dc5ldo", 0x10, (1 << 0), (1 << 0), (0 << 0),
101ae0af167Suaa 	  0x1c, 0x07, 700000, 100000, 8 },
102bad8128fSkettenis 	{ "aldo1", 0x10, (1 << 6), (1 << 6), (0 << 6),
103ae0af167Suaa 	  0x28, 0x1f, 700000, 100000, 27 },
104bad8128fSkettenis 	{ "aldo2", 0x10, (1 << 7), (1 << 7), (0 << 7),
105ae0af167Suaa 	  0x29, 0x1f, 700000, 100000, 27 },
106bad8128fSkettenis 	{ "aldo3", 0x13, (1 << 7), (1 << 7), (0 << 7),
107ae0af167Suaa 	  0x2a, 0x1f, 700000, 100000, 27 },
108bad8128fSkettenis 	{ "dldo1", 0x12, (1 << 3), (1 << 3), (0 << 3),
109ae0af167Suaa 	  0x15, 0x1f, 700000, 100000, 27 },
110bad8128fSkettenis 	{ "dldo2", 0x12, (1 << 4), (1 << 4), (0 << 4),
111ae0af167Suaa 	  0x16, 0x1f, 700000, 100000, 27 },
112bad8128fSkettenis 	{ "dldo3", 0x12, (1 << 5), (1 << 5), (0 << 5),
113ae0af167Suaa 	  0x17, 0x1f, 700000, 100000, 27 },
114bad8128fSkettenis 	{ "dldo4", 0x12, (1 << 6), (1 << 6), (0 << 6),
115ae0af167Suaa 	  0x18, 0x1f, 700000, 100000, 27 },
116bad8128fSkettenis 	{ "eldo1", 0x12, (1 << 0), (1 << 0), (0 << 0),
117ae0af167Suaa 	  0x19, 0x1f, 700000, 100000, 27 },
118bad8128fSkettenis 	{ "eldo2", 0x12, (1 << 1), (1 << 1), (0 << 1),
119ae0af167Suaa 	  0x1a, 0x1f, 700000, 100000, 27 },
120bad8128fSkettenis 	{ "eldo3", 0x12, (1 << 2), (1 << 2), (0 << 2),
121ae0af167Suaa 	  0x1b, 0x1f, 700000, 100000, 27 },
122bad8128fSkettenis 	{ "ldo_io0", 0x90, 0x07, 0x03, 0x04,
123ae0af167Suaa 	  0x91, 0x1f, 700000, 100000, 27 },
124bad8128fSkettenis 	{ "ldo_io1", 0x92, 0x07, 0x03, 0x04,
125ae0af167Suaa 	  0x93, 0x1f, 700000, 100000, 27 },
126bad8128fSkettenis 	{ NULL }
127bad8128fSkettenis };
128bad8128fSkettenis 
12911ace47bSuaa const struct axppmic_regdata axp313a_regdata[] = {
13011ace47bSuaa 	/* dcdc1: 1.6-3.4V (100mV step) not supported */
13111ace47bSuaa 	{ "dcdc1", 0x10, (1 << 0), (1 << 0), (0 << 0),
13211ace47bSuaa 	  0x13, 0x7f, 500000, 10000, 71, 122000, 20000, 17 },
13311ace47bSuaa 	{ "dcdc2", 0x10, (1 << 1), (1 << 1), (0 << 1),
13411ace47bSuaa 	  0x14, 0x7f, 500000, 10000, 71, 122000, 20000, 17 },
13511ace47bSuaa 	{ "dcdc3", 0x10, (1 << 2), (1 << 2), (0 << 2),
13611ace47bSuaa 	  0x15, 0x7f, 500000, 10000, 71, 122000, 20000, 32 },
13711ace47bSuaa 	{ "aldo1", 0x10, (1 << 3), (1 << 3), (0 << 3),
13811ace47bSuaa 	  0x16, 0x1f, 500000, 100000, 31 },
13911ace47bSuaa 	{ "dldo1", 0x10, (1 << 4), (1 << 4), (0 << 4),
14011ace47bSuaa 	  0x17, 0x1f, 500000, 100000, 31 },
14111ace47bSuaa 	{ NULL }
14211ace47bSuaa };
14311ace47bSuaa 
14437c734d3Snaddy const struct axppmic_regdata axp803_regdata[] = {
145ef258573Skettenis 	{ "dcdc1", 0x10, (1 << 0), (1 << 0), (0 << 0),
146ae0af167Suaa 	  0x20, 0x1f, 1600000, 100000, 19 },
147ef258573Skettenis 	{ "dcdc2", 0x10, (1 << 1), (1 << 1), (0 << 1),
148ae0af167Suaa 	  0x21, 0x7f, 500000, 10000, 71, 1220000, 20000, 5 },
149ef258573Skettenis 	{ "dcdc3", 0x10, (1 << 2), (1 << 2), (0 << 2),
150ae0af167Suaa 	  0x22, 0x7f, 500000, 10000, 71, 1220000, 20000, 5 },
151ef258573Skettenis 	{ "dcdc4", 0x10, (1 << 3), (1 << 3), (0 << 3),
152ae0af167Suaa 	  0x23, 0x7f, 500000, 10000, 71, 1220000, 20000, 5 },
153ef258573Skettenis 	{ "dcdc5", 0x10, (1 << 4), (1 << 4), (0 << 4),
154ae0af167Suaa 	  0x24, 0x7f, 800000, 10000, 33, 1140000, 20000, 36 },
155ef258573Skettenis 	{ "dcdc6", 0x10, (1 << 5), (1 << 5), (0 << 5),
156ae0af167Suaa 	  0x25, 0x7f, 600000, 10000, 51, 1120000, 20000, 21 },
157ef258573Skettenis 	{ "dc1sw", 0x12, (1 << 7), (1 << 7), (0 << 7) },
158ef258573Skettenis 	{ "aldo1", 0x13, (1 << 5), (1 << 5), (0 << 5),
159ae0af167Suaa 	  0x28, 0x1f, 700000, 100000, 27 },
160ef258573Skettenis 	{ "aldo2", 0x13, (1 << 6), (1 << 6), (0 << 6),
161ae0af167Suaa 	  0x29, 0x1f, 700000, 100000, 27 },
162ef258573Skettenis 	{ "aldo3", 0x13, (1 << 7), (1 << 7), (0 << 7),
163ae0af167Suaa 	  0x2a, 0x1f, 700000, 100000, 27 },
164ef258573Skettenis 	{ "dldo1", 0x12, (1 << 3), (1 << 3), (0 << 3),
165ae0af167Suaa 	  0x15, 0x1f, 700000, 100000, 27 },
166ef258573Skettenis 	{ "dldo2", 0x12, (1 << 4), (1 << 4), (0 << 4),
167ae0af167Suaa 	  0x16, 0x1f, 700000, 100000, 27, 3400000, 200000, 5 },
168ef258573Skettenis 	{ "dldo3", 0x12, (1 << 5), (1 << 5), (0 << 5),
169ae0af167Suaa 	  0x17, 0x1f, 700000, 100000, 27 },
170ef258573Skettenis 	{ "dldo4", 0x12, (1 << 6), (1 << 6), (0 << 6),
171ae0af167Suaa 	  0x18, 0x1f, 700000, 100000, 27 },
172ef258573Skettenis 	{ "eldo1", 0x12, (1 << 0), (1 << 0), (0 << 0),
173ae0af167Suaa 	  0x19, 0x1f, 700000, 50000, 25 },
174ef258573Skettenis 	{ "eldo2", 0x12, (1 << 1), (1 << 1), (0 << 1),
175ae0af167Suaa 	  0x1a, 0x1f, 700000, 50000, 25 },
176ef258573Skettenis 	{ "eldo3", 0x12, (1 << 2), (1 << 2), (0 << 2),
177ae0af167Suaa 	  0x1b, 0x1f, 700000, 50000, 25 },
178ef258573Skettenis 	{ "fldo1", 0x13, (1 << 2), (1 << 2), (0 << 2),
179ae0af167Suaa 	  0x1c, 0x0f, 700000, 50000, 16 },
180ef258573Skettenis 	{ "fldo2", 0x13, (1 << 3), (1 << 3), (0 << 3),
181ae0af167Suaa 	  0x1d, 0x0f, 700000, 50000, 16 },
182ef258573Skettenis 	{ "ldo-io0", 0x90, 0x07, 0x03, 0x04,
183ae0af167Suaa 	  0x91, 0x1f, 700000, 100000, 27 },
184ef258573Skettenis 	{ "ldo-io1", 0x92, 0x07, 0x03, 0x04,
185ae0af167Suaa 	  0x93, 0x1f, 700000, 100000, 27 },
186ef258573Skettenis 	{ NULL }
187ef258573Skettenis };
188ef258573Skettenis 
18937c734d3Snaddy const struct axppmic_regdata axp806_regdata[] = {
190b393861dSkettenis 	{ "dcdca", 0x10, (1 << 0), (1 << 0), (0 << 0),
191ae0af167Suaa 	  0x12, 0x7f, 600000, 10000, 51, 1120000, 20000, 21 },
192b393861dSkettenis 	{ "dcdcb", 0x10, (1 << 1), (1 << 1), (0 << 1),
193ae0af167Suaa 	  0x13, 0x1f, 1000000, 50000, 32 },
194b393861dSkettenis 	{ "dcdcc", 0x10, (1 << 2), (1 << 2), (0 << 2),
195ae0af167Suaa 	  0x14, 0x7f, 600000, 10000, 51, 1120000, 20000, 21 },
196b393861dSkettenis 	{ "dcdcd", 0x10, (1 << 3), (1 << 3), (0 << 3),
197ae0af167Suaa 	  0x15, 0x3f, 600000, 20000, 46, 1600000, 100000, 18 },
198b393861dSkettenis 	{ "dcdce", 0x10, (1 << 4), (1 << 4), (0 << 4),
199ae0af167Suaa 	  0x16, 0x1f, 1100000, 100000, 24 },
200b393861dSkettenis 	{ "aldo1", 0x10, (1 << 5), (1 << 5), (0 << 5),
201ae0af167Suaa 	  0x17, 0x1f, 700000, 100000, 27 },
202b393861dSkettenis 	{ "aldo2", 0x10, (1 << 6), (1 << 6), (0 << 6),
203ae0af167Suaa 	  0x18, 0x1f, 700000, 100000, 27 },
204b393861dSkettenis 	{ "aldo3", 0x10, (1 << 7), (1 << 7), (0 << 7),
205ae0af167Suaa 	  0x19, 0x1f, 700000, 100000, 27 },
206b393861dSkettenis 	{ "bldo1", 0x11, (1 << 0), (1 << 0), (0 << 0),
207ae0af167Suaa 	  0x20, 0x0f, 700000, 100000, 13 },
208b393861dSkettenis 	{ "bldo2", 0x11, (1 << 1), (1 << 1), (0 << 1),
209ae0af167Suaa 	  0x21, 0x0f, 700000, 100000, 13 },
210b393861dSkettenis 	{ "bldo3", 0x11, (1 << 2), (1 << 2), (0 << 2),
211ae0af167Suaa 	  0x22, 0x0f, 700000, 100000, 13 },
212b393861dSkettenis 	{ "bldo4", 0x11, (1 << 3), (1 << 3), (0 << 3),
213ae0af167Suaa 	  0x23, 0x0f, 700000, 100000, 13 },
214b393861dSkettenis 	{ "cldo1", 0x11, (1 << 4), (1 << 4), (0 << 4),
215ae0af167Suaa 	  0x24, 0x1f, 700000, 100000 , 27},
216b393861dSkettenis 	{ "cldo2", 0x11, (1 << 5), (1 << 5), (0 << 5),
217ae0af167Suaa 	  0x25, 0x1f, 700000, 100000, 28, 3600000, 200000, 4 },
218b393861dSkettenis 	{ "cldo3", 0x11, (1 << 6), (1 << 6), (0 << 6),
219ae0af167Suaa 	  0x26, 0x1f, 700000, 100000, 27 },
220b393861dSkettenis 	{ "sw", 0x11, (1 << 7), (1 << 7), (0 << 7) },
221b393861dSkettenis 	{ NULL }
222b393861dSkettenis };
223b393861dSkettenis 
22437c734d3Snaddy const struct axppmic_regdata axp809_regdata[] = {
225b393861dSkettenis 	{ "dcdc1", 0x10, (1 << 1), (1 << 1), (0 << 1),
226ae0af167Suaa 	  0x21, 0x1f, 1600000, 100000, 19 },
227b393861dSkettenis 	{ "dcdc2", 0x10, (1 << 2), (1 << 2), (0 << 2),
228ae0af167Suaa 	  0x22, 0x3f, 600000, 20000, 48 },
229b393861dSkettenis 	{ "dcdc3", 0x10, (1 << 3), (1 << 3), (0 << 3),
230ae0af167Suaa 	  0x23, 0x3f, 600000, 20000, 64 },
231b393861dSkettenis 	{ "dcdc4", 0x10, (1 << 4), (1 << 4), (0 << 4),
232ae0af167Suaa 	  0x24, 0x3f, 600000, 20000, 48, 1800000, 100000, 9 },
233b393861dSkettenis 	{ "dcdc5", 0x10, (1 << 5), (1 << 5), (0 << 5),
234ae0af167Suaa 	  0x25, 0x1f, 1000000, 50000, 32 },
235b393861dSkettenis 	{ "dc5ldo", 0x10, (1 << 0), (1 << 0), (0 << 0),
236ae0af167Suaa 	  0x1c, 0x07, 700000, 100000, 8 },
237b393861dSkettenis 	{ "aldo1", 0x10, (1 << 6), (1 << 6), (0 << 6),
238ae0af167Suaa 	  0x28, 0x1f, 700000, 100000, 27 },
239b393861dSkettenis 	{ "aldo2", 0x10, (1 << 7), (1 << 7), (0 << 7),
240ae0af167Suaa 	  0x29, 0x1f, 700000, 100000, 27 },
241b393861dSkettenis 	{ "aldo3", 0x12, (1 << 5), (1 << 5), (0 << 5),
242ae0af167Suaa 	  0x2a, 0x1f, 700000, 100000, 27 },
243b393861dSkettenis 	{ "dldo1", 0x12, (1 << 3), (1 << 3), (0 << 3),
244ae0af167Suaa 	  0x15, 0x1f, 700000, 100000, 27, 3400000, 200000, 5 },
245b393861dSkettenis 	{ "dldo2", 0x12, (1 << 4), (1 << 4), (0 << 4),
246ae0af167Suaa 	  0x16, 0x1f, 700000, 100000, 27 },
247b393861dSkettenis 	{ "eldo1", 0x12, (1 << 0), (1 << 0), (0 << 0),
248ae0af167Suaa 	  0x19, 0x1f, 700000, 100000, 27 },
249b393861dSkettenis 	{ "eldo2", 0x12, (1 << 1), (1 << 1), (0 << 1),
250ae0af167Suaa 	  0x1a, 0x1f, 700000, 100000, 27 },
251b393861dSkettenis 	{ "eldo3", 0x12, (1 << 2), (1 << 2), (0 << 2),
252ae0af167Suaa 	  0x1b, 0x1f, 700000, 100000, 27 },
253b393861dSkettenis 	{ "ldo_io0", 0x90, 0x07, 0x03, 0x04,
254ae0af167Suaa 	  0x91, 0x1f, 700000, 100000, 27 },
255b393861dSkettenis 	{ "ldo_io1", 0x92, 0x07, 0x03, 0x04,
256ae0af167Suaa 	  0x93, 0x1f, 700000, 100000, 27 },
257b393861dSkettenis 	{ NULL }
258b393861dSkettenis };
259b393861dSkettenis 
260977d3b0bSkettenis const struct axppmic_regdata axp15060_regdata[] = {
261977d3b0bSkettenis 	{ "dcdc1", 0x10, (1 << 0), (1 << 0), (0 << 0),
262977d3b0bSkettenis 	  0x13, 0x1f, 15000000, 100000, 20 },
263977d3b0bSkettenis 	{ "dcdc2", 0x10, (1 << 1), (1 << 1), (0 << 1),
264977d3b0bSkettenis 	  0x14, 0x7f, 500000, 10000, 71, 1220000, 20000, 17 },
265977d3b0bSkettenis 	{ "dcdc3", 0x10, (1 << 2), (1 << 2), (0 << 2),
266977d3b0bSkettenis 	  0x15, 0x7f, 500000, 10000, 71, 1220000, 20000, 17 },
267977d3b0bSkettenis 	{ "dcdc4", 0x10, (1 << 3), (1 << 3), (0 << 3),
268977d3b0bSkettenis 	  0x16, 0x7f, 500000, 10000, 71, 1220000, 20000, 17 },
269977d3b0bSkettenis 	{ "dcdc5", 0x10, (1 << 4), (1 << 4), (0 << 4),
270977d3b0bSkettenis 	  0x17, 0x7f, 800000, 10000, 33, 1140000, 20000, 36 },
271977d3b0bSkettenis 	{ "dcdc6", 0x10, (1 << 5), (1 << 5), (0 << 5),
272977d3b0bSkettenis 	  0x18, 0x1f, 500000, 100000, 30 },
273977d3b0bSkettenis 	{ "aldo1", 0x11, (1 << 0), (1 << 0), (0 << 0),
274977d3b0bSkettenis 	  0x19, 0x1f, 700000, 100000, 27 },
275977d3b0bSkettenis 	{ "aldo2", 0x11, (1 << 1), (1 << 1), (0 << 1),
276977d3b0bSkettenis 	  0x20, 0x1f, 700000, 100000, 27 },
277977d3b0bSkettenis 	{ "aldo3", 0x11, (1 << 2), (1 << 2), (0 << 2),
278977d3b0bSkettenis 	  0x21, 0x1f, 700000, 100000, 27 },
279977d3b0bSkettenis 	{ "aldo4", 0x11, (1 << 3), (1 << 3), (0 << 3),
280977d3b0bSkettenis 	  0x22, 0x1f, 700000, 100000, 27 },
281977d3b0bSkettenis 	{ "aldo5", 0x11, (1 << 4), (1 << 4), (0 << 4),
282977d3b0bSkettenis 	  0x23, 0x1f, 700000, 100000, 27 },
283977d3b0bSkettenis 	{ "bldo1", 0x11, (1 << 5), (1 << 5), (0 << 5),
284977d3b0bSkettenis 	  0x24, 0x1f, 700000, 100000, 27 },
285977d3b0bSkettenis 	{ "bldo2", 0x11, (1 << 6), (1 << 6), (0 << 6),
286977d3b0bSkettenis 	  0x25, 0x1f, 700000, 100000, 27 },
287977d3b0bSkettenis 	{ "bldo3", 0x11, (1 << 7), (1 << 7), (0 << 7),
288977d3b0bSkettenis 	  0x26, 0x1f, 700000, 100000, 27 },
289977d3b0bSkettenis 	{ "bldo4", 0x12, (1 << 0), (1 << 0), (0 << 0),
290977d3b0bSkettenis 	  0x27, 0x1f, 700000, 100000, 27 },
291977d3b0bSkettenis 	{ "bldo5", 0x12, (1 << 1), (1 << 1), (0 << 1),
292977d3b0bSkettenis 	  0x28, 0x1f, 700000, 100000, 27 },
293977d3b0bSkettenis 	{ "cldo1", 0x12, (1 << 2), (1 << 2), (0 << 2),
294977d3b0bSkettenis 	  0x29, 0x1f, 700000, 100000, 27 },
295977d3b0bSkettenis 	{ "cldo2", 0x12, (1 << 3), (1 << 3), (0 << 3),
296977d3b0bSkettenis 	  0x2a, 0x1f, 700000, 100000, 27 },
297977d3b0bSkettenis 	{ "cldo3", 0x12, (1 << 4), (1 << 4), (0 << 4),
298977d3b0bSkettenis 	  0x2b, 0x1f, 700000, 100000, 27 },
299977d3b0bSkettenis 	{ "cldo4", 0x12, (1 << 5), (1 << 5), (0 << 5),
300977d3b0bSkettenis 	  0x2d, 0x3f, 700000, 100000, 36 },
301977d3b0bSkettenis 	{ "cpusldo", 0x12, (1 << 6), (1 << 6), (0 << 6),
302977d3b0bSkettenis 	  0x2e, 0x0f, 700000, 50000, 15 },
303977d3b0bSkettenis 	{ "sw", 0x12, (1 << 7), (1 << 7), (0 << 7) },
304977d3b0bSkettenis 	{ NULL }
305977d3b0bSkettenis };
306977d3b0bSkettenis 
307bad8128fSkettenis /* Sensors for AXP209 and AXP221/AXP809. */
308de7daf7eSkettenis 
309e6b4a485Skettenis #define AXPPMIC_NSENSORS 12
310de7daf7eSkettenis 
311de7daf7eSkettenis struct axppmic_sensdata {
312de7daf7eSkettenis 	const char *name;
313de7daf7eSkettenis 	enum sensor_type type;
314de7daf7eSkettenis 	uint8_t reg;
315de7daf7eSkettenis 	uint64_t base, delta;
316de7daf7eSkettenis };
317de7daf7eSkettenis 
31837c734d3Snaddy const struct axppmic_sensdata axp209_sensdata[] = {
319de7daf7eSkettenis 	{ "ACIN", SENSOR_INDICATOR, 0x00, (1 << 7), (1 << 6) },
320de7daf7eSkettenis 	{ "VBUS", SENSOR_INDICATOR, 0x00, (1 << 5), (1 << 4) },
321de7daf7eSkettenis 	{ "ACIN", SENSOR_VOLTS_DC, 0x56, 0, 1700 },
322de7daf7eSkettenis 	{ "ACIN", SENSOR_AMPS, 0x58, 0, 625 },
323de7daf7eSkettenis 	{ "VBUS", SENSOR_VOLTS_DC, 0x5a, 0, 1700 },
324de7daf7eSkettenis 	{ "VBUS", SENSOR_AMPS, 0x5c, 0, 375 },
325de7daf7eSkettenis 	{ "", SENSOR_TEMP, 0x5e, 128450000, 100000 },
326de7daf7eSkettenis 	{ "APS", SENSOR_VOLTS_DC, 0x7e, 0, 1400 },
327de7daf7eSkettenis 	{ NULL }
328de7daf7eSkettenis };
329de7daf7eSkettenis 
33037c734d3Snaddy const struct axppmic_sensdata axp221_sensdata[] = {
3313f2b37c9Skettenis 	{ "ACIN", SENSOR_INDICATOR, 0x00, (1 << 7), (1 << 6) },
3323f2b37c9Skettenis 	{ "VBUS", SENSOR_INDICATOR, 0x00, (1 << 5), (1 << 4) },
3333f2b37c9Skettenis 	{ "", SENSOR_TEMP, 0x56, 5450000, 105861 },
3343f2b37c9Skettenis 	{ NULL }
3353f2b37c9Skettenis };
3363f2b37c9Skettenis 
33737c734d3Snaddy const struct axppmic_sensdata axp803_sensdata[] = {
338ef258573Skettenis 	{ "ACIN", SENSOR_INDICATOR, 0x00, (1 << 7), (1 << 6) },
339ef258573Skettenis 	{ "VBUS", SENSOR_INDICATOR, 0x00, (1 << 5), (1 << 4) },
340ef258573Skettenis 	{ "", SENSOR_TEMP, 0x56, 5450000, 106250 },
341ef258573Skettenis 	{ NULL }
342ef258573Skettenis };
343ef258573Skettenis 
34437c734d3Snaddy const struct axppmic_sensdata axp803_battery_sensdata[] = {
345e6b4a485Skettenis 	{ "ACIN", SENSOR_INDICATOR, 0x00, (1 << 7), (1 << 6) },
346e6b4a485Skettenis 	{ "VBUS", SENSOR_INDICATOR, 0x00, (1 << 5), (1 << 4) },
347e6b4a485Skettenis 	{ "", SENSOR_TEMP, 0x56, 5450000, 106250 },
348e6b4a485Skettenis 	{ "battery present", SENSOR_INDICATOR, 0x01, (1 << 5), (1 << 4) },
349e6b4a485Skettenis 	{ "battery charging", SENSOR_INDICATOR, 0x01, (1 << 6), (1 << 6) },
350e6b4a485Skettenis 	{ "battery percent", SENSOR_PERCENT, 0xb9, 0x7f, (1 << 7) },
351e6b4a485Skettenis 	{ "battery voltage", SENSOR_VOLTS_DC, 0x78, 0x00, 1100 },
352e6b4a485Skettenis 	{ "battery charging current", SENSOR_AMPS, 0x7a, 0x00, 1000 },
353e6b4a485Skettenis 	{ "battery discharging current", SENSOR_AMPS, 0x7c, 0x00, 1000 },
354e6b4a485Skettenis 	{ "battery maximum capacity", SENSOR_AMPHOUR, 0xe0, 0x00, 1456 },
355e6b4a485Skettenis 	{ "battery current capacity", SENSOR_AMPHOUR, 0xe2, 0x00, 1456 },
356e6b4a485Skettenis 	{ NULL }
357e6b4a485Skettenis };
358e6b4a485Skettenis 
359b393861dSkettenis struct axppmic_device {
360b393861dSkettenis 	const char *name;
361b393861dSkettenis 	const char *chip;
36237c734d3Snaddy 	const struct axppmic_regdata *regdata;
36337c734d3Snaddy 	const struct axppmic_sensdata *sensdata;
364b393861dSkettenis };
365b393861dSkettenis 
36637c734d3Snaddy const struct axppmic_device axppmic_devices[] = {
367de7daf7eSkettenis 	{ "x-powers,axp152", "AXP152" },
368de7daf7eSkettenis 	{ "x-powers,axp209", "AXP209", axp209_regdata, axp209_sensdata },
369bad8128fSkettenis 	{ "x-powers,axp221", "AXP221", axp221_regdata, axp221_sensdata },
370bad8128fSkettenis 	{ "x-powers,axp223", "AXP223", axp221_regdata, axp221_sensdata },
371ae0af167Suaa 	{ "x-powers,axp305", "AXP305", axp806_regdata },
37211ace47bSuaa 	{ "x-powers,axp313a", "AXP313A", axp313a_regdata },
373ef258573Skettenis 	{ "x-powers,axp803", "AXP803", axp803_regdata, axp803_sensdata },
374830dc0cdSuaa 	{ "x-powers,axp805", "AXP805", axp806_regdata },
375b393861dSkettenis 	{ "x-powers,axp806", "AXP806", axp806_regdata },
376977d3b0bSkettenis 	{ "x-powers,axp809", "AXP809", axp809_regdata, axp221_sensdata },
377977d3b0bSkettenis 	{ "x-powers,axp15060", "AXP15060", axp15060_regdata },
378b393861dSkettenis };
379b393861dSkettenis 
380b393861dSkettenis const struct axppmic_device *
381b393861dSkettenis axppmic_lookup(const char *name)
382b393861dSkettenis {
383b393861dSkettenis 	int i;
384b393861dSkettenis 
385b393861dSkettenis 	for (i = 0; i < nitems(axppmic_devices); i++) {
386b393861dSkettenis 		if (strcmp(name, axppmic_devices[i].name) == 0)
387b393861dSkettenis 			return &axppmic_devices[i];
388b393861dSkettenis 	}
389b393861dSkettenis 
390b393861dSkettenis 	return NULL;
391b393861dSkettenis }
392b393861dSkettenis 
393b393861dSkettenis struct axppmic_softc {
394b393861dSkettenis 	struct device	sc_dev;
395b393861dSkettenis 	void		*sc_cookie;
396de7daf7eSkettenis 	uint16_t 	sc_addr;
3977a19eddcSkettenis 	const char	*sc_name;
398b393861dSkettenis 
399de7daf7eSkettenis 	uint8_t		(*sc_read)(struct axppmic_softc *, uint8_t);
400de7daf7eSkettenis 	void		(*sc_write)(struct axppmic_softc *, uint8_t, uint8_t);
40137c734d3Snaddy 	const struct axppmic_regdata *sc_regdata;
40237c734d3Snaddy 	const struct axppmic_sensdata *sc_sensdata;
403de7daf7eSkettenis 
404de7daf7eSkettenis 	struct ksensor	sc_sensor[AXPPMIC_NSENSORS];
405de7daf7eSkettenis 	struct ksensordev sc_sensordev;
406e6b4a485Skettenis 
407e6b4a485Skettenis 	uint8_t 	sc_warn;
408e6b4a485Skettenis 	uint8_t		sc_crit;
409b393861dSkettenis };
410b393861dSkettenis 
41130025dadSpatrick static inline uint8_t
412b393861dSkettenis axppmic_read_reg(struct axppmic_softc *sc, uint8_t reg)
413b393861dSkettenis {
414de7daf7eSkettenis 	return sc->sc_read(sc, reg);
415b393861dSkettenis }
416b393861dSkettenis 
41730025dadSpatrick static inline void
418b393861dSkettenis axppmic_write_reg(struct axppmic_softc *sc, uint8_t reg, uint8_t value)
419b393861dSkettenis {
420de7daf7eSkettenis 	sc->sc_write(sc, reg, value);
421b393861dSkettenis }
422b393861dSkettenis 
423de7daf7eSkettenis void	axppmic_attach_common(struct axppmic_softc *, const char *, int);
4247a19eddcSkettenis int	axppmic_activate(struct device *, int);
425de7daf7eSkettenis 
426de7daf7eSkettenis /* I2C interface */
427de7daf7eSkettenis 
428de7daf7eSkettenis int	axppmic_i2c_match(struct device *, void *, void *);
429de7daf7eSkettenis void	axppmic_i2c_attach(struct device *, struct device *, void *);
430de7daf7eSkettenis 
4319fdf0c62Smpi const struct cfattach axppmic_ca = {
4327a19eddcSkettenis 	sizeof(struct axppmic_softc), axppmic_i2c_match, axppmic_i2c_attach,
4337a19eddcSkettenis 	NULL, axppmic_activate
434de7daf7eSkettenis };
435de7daf7eSkettenis 
436de7daf7eSkettenis struct cfdriver axppmic_cd = {
437de7daf7eSkettenis 	NULL, "axppmic", DV_DULL
438de7daf7eSkettenis };
439de7daf7eSkettenis 
440de7daf7eSkettenis uint8_t	axppmic_i2c_read(struct axppmic_softc *, uint8_t);
441de7daf7eSkettenis void	axppmic_i2c_write(struct axppmic_softc *, uint8_t, uint8_t);
442de7daf7eSkettenis 
443de7daf7eSkettenis int
444de7daf7eSkettenis axppmic_i2c_match(struct device *parent, void *match, void *aux)
445de7daf7eSkettenis {
446de7daf7eSkettenis 	struct i2c_attach_args *ia = aux;
447de7daf7eSkettenis 
448de7daf7eSkettenis 	if (axppmic_lookup(ia->ia_name))
449de7daf7eSkettenis 		return 1;
450de7daf7eSkettenis 	return 0;
451de7daf7eSkettenis }
452de7daf7eSkettenis 
453de7daf7eSkettenis void
454de7daf7eSkettenis axppmic_i2c_attach(struct device *parent, struct device *self, void *aux)
455de7daf7eSkettenis {
456de7daf7eSkettenis 	struct axppmic_softc *sc = (struct axppmic_softc *)self;
457de7daf7eSkettenis 	struct i2c_attach_args *ia = aux;
458de7daf7eSkettenis 	int node = *(int *)ia->ia_cookie;
459de7daf7eSkettenis 
460de7daf7eSkettenis 	sc->sc_cookie = ia->ia_tag;
461de7daf7eSkettenis 	sc->sc_addr = ia->ia_addr;
462de7daf7eSkettenis 	sc->sc_read = axppmic_i2c_read;
463de7daf7eSkettenis 	sc->sc_write = axppmic_i2c_write;
464de7daf7eSkettenis 
465de7daf7eSkettenis 	axppmic_attach_common(sc, ia->ia_name, node);
466de7daf7eSkettenis }
467de7daf7eSkettenis 
468de7daf7eSkettenis uint8_t
469de7daf7eSkettenis axppmic_i2c_read(struct axppmic_softc *sc, uint8_t reg)
470de7daf7eSkettenis {
471de7daf7eSkettenis 	i2c_tag_t tag = sc->sc_cookie;
472de7daf7eSkettenis 	int flags = cold ? I2C_F_POLL : 0;
473de7daf7eSkettenis 	int error;
474de7daf7eSkettenis 	uint8_t value;
475de7daf7eSkettenis 
476de7daf7eSkettenis 	iic_acquire_bus(tag, flags);
477de7daf7eSkettenis 	error = iic_smbus_read_byte(tag, sc->sc_addr, reg, &value, flags);
478de7daf7eSkettenis 	iic_release_bus(tag, flags);
479de7daf7eSkettenis 	if (error) {
480bad8128fSkettenis 		printf("%s: SMBus read byte from 0x%02x failed\n",
481bad8128fSkettenis 		    sc->sc_dev.dv_xname, reg);
482de7daf7eSkettenis 		return 0xff;
483de7daf7eSkettenis 	}
484de7daf7eSkettenis 
485de7daf7eSkettenis 	return value;
486de7daf7eSkettenis }
487de7daf7eSkettenis 
488de7daf7eSkettenis void
489de7daf7eSkettenis axppmic_i2c_write(struct axppmic_softc *sc, uint8_t reg, uint8_t value)
490de7daf7eSkettenis {
491de7daf7eSkettenis 	i2c_tag_t tag = sc->sc_cookie;
492de7daf7eSkettenis 	int flags = cold ? I2C_F_POLL : 0;
493de7daf7eSkettenis 	int error;
494de7daf7eSkettenis 
495de7daf7eSkettenis 	iic_acquire_bus(tag, flags);
496de7daf7eSkettenis 	error = iic_smbus_write_byte(tag, sc->sc_addr, reg, value, flags);
497de7daf7eSkettenis 	iic_release_bus(tag, flags);
498de7daf7eSkettenis 	if (error)
499bad8128fSkettenis 		printf("%s: SMBus write byte to 0x%02x failed\n",
500bad8128fSkettenis 		    sc->sc_dev.dv_xname, reg);
501de7daf7eSkettenis }
502de7daf7eSkettenis 
503de7daf7eSkettenis /* RSB interface */
504de7daf7eSkettenis 
505a20bb377Skettenis #include "sxirsb.h"
506a20bb377Skettenis 
507a20bb377Skettenis #if NSXIRSB > 0
508a20bb377Skettenis 
509de7daf7eSkettenis int	axppmic_rsb_match(struct device *, void *, void *);
510de7daf7eSkettenis void	axppmic_rsb_attach(struct device *, struct device *, void *);
511b393861dSkettenis 
5129fdf0c62Smpi const struct cfattach axppmic_rsb_ca = {
5137a19eddcSkettenis 	sizeof(struct axppmic_softc), axppmic_rsb_match, axppmic_rsb_attach,
5147a19eddcSkettenis 	NULL, axppmic_activate
515b393861dSkettenis };
516b393861dSkettenis 
517de7daf7eSkettenis uint8_t	axppmic_rsb_read(struct axppmic_softc *, uint8_t);
518de7daf7eSkettenis void	axppmic_rsb_write(struct axppmic_softc *, uint8_t, uint8_t);
519b393861dSkettenis 
520b393861dSkettenis int
521de7daf7eSkettenis axppmic_rsb_match(struct device *parent, void *match, void *aux)
522b393861dSkettenis {
523b393861dSkettenis 	struct rsb_attach_args *ra = aux;
524b393861dSkettenis 
525b393861dSkettenis 	if (axppmic_lookup(ra->ra_name))
526b393861dSkettenis 		return 1;
527b393861dSkettenis 	return 0;
528b393861dSkettenis }
529b393861dSkettenis 
530b393861dSkettenis void
531de7daf7eSkettenis axppmic_rsb_attach(struct device *parent, struct device *self, void *aux)
532b393861dSkettenis {
533b393861dSkettenis 	struct axppmic_softc *sc = (struct axppmic_softc *)self;
534b393861dSkettenis 	struct rsb_attach_args *ra = aux;
535b393861dSkettenis 
536b393861dSkettenis 	sc->sc_cookie = ra->ra_cookie;
537de7daf7eSkettenis 	sc->sc_addr = ra->ra_rta;
538de7daf7eSkettenis 	sc->sc_read = axppmic_rsb_read;
539de7daf7eSkettenis 	sc->sc_write = axppmic_rsb_write;
540b393861dSkettenis 
541de7daf7eSkettenis 	axppmic_attach_common(sc, ra->ra_name, ra->ra_node);
542de7daf7eSkettenis }
543de7daf7eSkettenis 
544de7daf7eSkettenis uint8_t
545de7daf7eSkettenis axppmic_rsb_read(struct axppmic_softc *sc, uint8_t reg)
546de7daf7eSkettenis {
547de7daf7eSkettenis 	return rsb_read_1(sc->sc_cookie, sc->sc_addr, reg);
548de7daf7eSkettenis }
549de7daf7eSkettenis 
550de7daf7eSkettenis void
551de7daf7eSkettenis axppmic_rsb_write(struct axppmic_softc *sc, uint8_t reg, uint8_t value)
552de7daf7eSkettenis {
553de7daf7eSkettenis 	rsb_write_1(sc->sc_cookie, sc->sc_addr, reg, value);
554de7daf7eSkettenis }
555de7daf7eSkettenis 
556a20bb377Skettenis #endif
557a20bb377Skettenis 
558de7daf7eSkettenis /* Common code */
559de7daf7eSkettenis 
560e6b4a485Skettenis void	axppmic_attach_node(struct axppmic_softc *, int);
561de7daf7eSkettenis void	axppmic_attach_regulators(struct axppmic_softc *, int);
562de7daf7eSkettenis void	axppmic_attach_sensors(struct axppmic_softc *);
563de7daf7eSkettenis 
564de7daf7eSkettenis struct axppmic_softc *axppmic_sc;
565de7daf7eSkettenis void	axp209_powerdown(void);
566de7daf7eSkettenis 
567de7daf7eSkettenis void
568de7daf7eSkettenis axppmic_attach_common(struct axppmic_softc *sc, const char *name, int node)
569de7daf7eSkettenis {
570de7daf7eSkettenis 	const struct axppmic_device *device;
571e6b4a485Skettenis 	int child;
572de7daf7eSkettenis 
573de7daf7eSkettenis 	device = axppmic_lookup(name);
574b393861dSkettenis 	printf(": %s\n", device->chip);
575b393861dSkettenis 
5767a19eddcSkettenis 	sc->sc_name = device->name;
577b393861dSkettenis 	sc->sc_regdata = device->regdata;
578de7daf7eSkettenis 	sc->sc_sensdata = device->sensdata;
579b393861dSkettenis 
580b393861dSkettenis 	/* Switch AXP806 into master or slave mode. */
581ae0af167Suaa 	if (strcmp(name, "x-powers,axp305") == 0 ||
582ae0af167Suaa 	    strcmp(name, "x-powers,axp805") == 0 ||
583830dc0cdSuaa 	    strcmp(name, "x-powers,axp806") == 0) {
584830dc0cdSuaa 	    if (OF_getproplen(node, "x-powers,master-mode") == 0 ||
585830dc0cdSuaa 	        OF_getproplen(node, "x-powers,self-working-mode") == 0) {
586b393861dSkettenis 			axppmic_write_reg(sc, AXP806_REG_ADDR_EXT,
587b393861dSkettenis 			    AXP806_REG_ADDR_EXT_MASTER_MODE);
588b393861dSkettenis 		} else {
589b393861dSkettenis 			axppmic_write_reg(sc, AXP806_REG_ADDR_EXT,
590b393861dSkettenis 			    AXP806_REG_ADDR_EXT_SLAVE_MODE);
591b393861dSkettenis 		}
592b393861dSkettenis 	}
593b393861dSkettenis 
5944b1a56afSjsg 	/* Enable data collection on AXP209. */
595de7daf7eSkettenis 	if (strcmp(name, "x-powers,axp209") == 0) {
596de7daf7eSkettenis 		uint8_t reg;
597de7daf7eSkettenis 
598de7daf7eSkettenis 		/* Turn on sampling of ACIN and VBUS voltage and current. */
599de7daf7eSkettenis 		reg = axppmic_read_reg(sc, AXP209_ADC_EN1);
600de7daf7eSkettenis 		reg |= AXP209_ADC_EN1_ACIN;
601de7daf7eSkettenis 		reg |= AXP209_ADC_EN1_VBUS;
602de7daf7eSkettenis 		axppmic_write_reg(sc, AXP209_ADC_EN1, reg);
603b393861dSkettenis 	}
604b393861dSkettenis 
605e6b4a485Skettenis 	/* Read battery warning levels on AXP803. */
606e6b4a485Skettenis 	if (strcmp(name, "x-powers,axp803") == 0) {
607e6b4a485Skettenis 		uint8_t value;
608e6b4a485Skettenis 
609e6b4a485Skettenis 		value = axppmic_read_reg(sc, AXP803_BAT_CAP_WARN);
610e6b4a485Skettenis 		sc->sc_warn = ((value & AXP803_BAT_CAP_WARN_LV1) >> 4);
611e6b4a485Skettenis 		sc->sc_warn += AXP803_BAT_CAP_WARN_LV1BASE;
612e6b4a485Skettenis 		sc->sc_crit = (value & AXP803_BAT_CAP_WARN_LV2);
613e6b4a485Skettenis 	}
614e6b4a485Skettenis 
615e6b4a485Skettenis 	for (child = OF_child(node); child; child = OF_peer(child))
616e6b4a485Skettenis 		axppmic_attach_node(sc, child);
617e6b4a485Skettenis 
618de7daf7eSkettenis 	if (sc->sc_regdata)
619de7daf7eSkettenis 		axppmic_attach_regulators(sc, node);
620de7daf7eSkettenis 
621de7daf7eSkettenis 	if (sc->sc_sensdata)
622de7daf7eSkettenis 		axppmic_attach_sensors(sc);
623de7daf7eSkettenis 
6247a19eddcSkettenis 	/* Disable all interrupts on AXP803. */
6257a19eddcSkettenis 	if (strcmp(name, "x-powers,axp803") == 0) {
6267a19eddcSkettenis 		axppmic_write_reg(sc, AXP803_IRQ1_EN, 0);
6277a19eddcSkettenis 		axppmic_write_reg(sc, AXP803_IRQ2_EN, 0);
6287a19eddcSkettenis 		axppmic_write_reg(sc, AXP803_IRQ3_EN, 0);
6297a19eddcSkettenis 		axppmic_write_reg(sc, AXP803_IRQ4_EN, 0);
6307a19eddcSkettenis 		axppmic_write_reg(sc, AXP803_IRQ5_EN, 0);
6317a19eddcSkettenis 		axppmic_write_reg(sc, AXP803_IRQ6_EN, 0);
6327a19eddcSkettenis 	}
6337a19eddcSkettenis 
634de7daf7eSkettenis #ifdef __armv7__
635de7daf7eSkettenis 	if (strcmp(name, "x-powers,axp152") == 0 ||
636de7daf7eSkettenis 	    strcmp(name, "x-powers,axp209") == 0) {
637de7daf7eSkettenis 		axppmic_sc = sc;
638de7daf7eSkettenis 		powerdownfn = axp209_powerdown;
639de7daf7eSkettenis 	}
640ef258573Skettenis #endif
64117b371d9Skettenis 
64217b371d9Skettenis #ifdef SUSPEND
64317b371d9Skettenis 	/* AXP803 can wake us up. */
64417b371d9Skettenis 	if (strcmp(name, "x-powers,axp803") == 0)
64517b371d9Skettenis 		device_register_wakeup(&sc->sc_dev);
64617b371d9Skettenis #endif
647de7daf7eSkettenis }
648de7daf7eSkettenis 
649e6b4a485Skettenis void
650e6b4a485Skettenis axppmic_attach_node(struct axppmic_softc *sc, int node)
651e6b4a485Skettenis {
652e6b4a485Skettenis 	char status[32];
653e6b4a485Skettenis 
654e6b4a485Skettenis 	if (OF_getprop(node, "status", status, sizeof(status)) > 0 &&
655e6b4a485Skettenis 	    strcmp(status, "disabled") == 0)
656e6b4a485Skettenis 		return;
657e6b4a485Skettenis 
658e6b4a485Skettenis 	if (OF_is_compatible(node, "x-powers,axp803-battery-power-supply"))
659e6b4a485Skettenis 		sc->sc_sensdata = axp803_battery_sensdata;
660e6b4a485Skettenis }
661e6b4a485Skettenis 
6627a19eddcSkettenis int
6637a19eddcSkettenis axppmic_activate(struct device *self, int act)
6647a19eddcSkettenis {
6657a19eddcSkettenis 	struct axppmic_softc *sc = (struct axppmic_softc *)self;
6667a19eddcSkettenis 
6677a19eddcSkettenis 	switch (act) {
6687a19eddcSkettenis 	case DVACT_SUSPEND:
6697a19eddcSkettenis 		if (strcmp(sc->sc_name, "x-powers,axp803") == 0) {
6707a19eddcSkettenis 			/* Enable interrupt for short power button press. */
6717a19eddcSkettenis 			axppmic_write_reg(sc, AXP803_IRQ5_STAT,
6727a19eddcSkettenis 			    AXP803_IRQ5_STAT_PEK_SHORT);
6737a19eddcSkettenis 			axppmic_write_reg(sc, AXP803_IRQ5_EN,
6747a19eddcSkettenis 			    AXP803_IRQ5_EN_PEK_SHORT);
6757a19eddcSkettenis 		}
6767a19eddcSkettenis 		break;
6777a19eddcSkettenis 	case DVACT_RESUME:
6787a19eddcSkettenis 		if (strcmp(sc->sc_name, "x-powers,axp803") == 0) {
6797a19eddcSkettenis 			/* Disable interrupt for short power button press. */
6807a19eddcSkettenis 			axppmic_write_reg(sc, AXP803_IRQ5_EN, 0);
6817a19eddcSkettenis 		}
6827a19eddcSkettenis 		break;
6837a19eddcSkettenis 	}
6847a19eddcSkettenis 
6857a19eddcSkettenis 	return 0;
6867a19eddcSkettenis }
6877a19eddcSkettenis 
688de7daf7eSkettenis /* Regulators */
689de7daf7eSkettenis 
690b393861dSkettenis struct axppmic_regulator {
691b393861dSkettenis 	struct axppmic_softc *ar_sc;
692b393861dSkettenis 
693b393861dSkettenis 	uint8_t ar_ereg, ar_emask;
694b393861dSkettenis 	uint8_t ar_eval, ar_dval;
695b393861dSkettenis 
696b393861dSkettenis 	uint8_t ar_vreg, ar_vmask;
697ae0af167Suaa 	uint32_t ar_base, ar_delta, ar_nsteps;
698ae0af167Suaa 	uint32_t ar_base2, ar_delta2, ar_nsteps2;
699b393861dSkettenis 
700b393861dSkettenis 	struct regulator_device ar_rd;
701b393861dSkettenis };
702b393861dSkettenis 
703de7daf7eSkettenis void	axppmic_attach_regulator(struct axppmic_softc *, int);
704b393861dSkettenis uint32_t axppmic_get_voltage(void *);
705b393861dSkettenis int	axppmic_set_voltage(void *, uint32_t);
706b393861dSkettenis int	axppmic_enable(void *, int);
707b393861dSkettenis 
708b393861dSkettenis void
709de7daf7eSkettenis axppmic_attach_regulators(struct axppmic_softc *sc, int node)
710de7daf7eSkettenis {
711de7daf7eSkettenis 	node = OF_getnodebyname(node, "regulators");
712de7daf7eSkettenis 	if (node == 0)
713de7daf7eSkettenis 		return;
714de7daf7eSkettenis 
715de7daf7eSkettenis 	for (node = OF_child(node); node; node = OF_peer(node))
716de7daf7eSkettenis 		axppmic_attach_regulator(sc, node);
717de7daf7eSkettenis }
718de7daf7eSkettenis 
719de7daf7eSkettenis void
720b393861dSkettenis axppmic_attach_regulator(struct axppmic_softc *sc, int node)
721b393861dSkettenis {
722b393861dSkettenis 	struct axppmic_regulator *ar;
723b393861dSkettenis 	char name[32];
724b393861dSkettenis 	int i;
725b393861dSkettenis 
726b393861dSkettenis 	name[0] = 0;
727b393861dSkettenis 	OF_getprop(node, "name", name, sizeof(name));
728b393861dSkettenis 	name[sizeof(name) - 1] = 0;
729b393861dSkettenis 	for (i = 0; sc->sc_regdata[i].name; i++) {
730b393861dSkettenis 		if (strcmp(sc->sc_regdata[i].name, name) == 0)
731b393861dSkettenis 			break;
732b393861dSkettenis 	}
733b393861dSkettenis 	if (sc->sc_regdata[i].name == NULL)
734b393861dSkettenis 		return;
735b393861dSkettenis 
736b393861dSkettenis 	ar = malloc(sizeof(*ar), M_DEVBUF, M_WAITOK | M_ZERO);
737b393861dSkettenis 	ar->ar_sc = sc;
738b393861dSkettenis 
739b393861dSkettenis 	ar->ar_ereg = sc->sc_regdata[i].ereg;
740b393861dSkettenis 	ar->ar_emask = sc->sc_regdata[i].emask;
741b393861dSkettenis 	ar->ar_eval = sc->sc_regdata[i].eval;
742b393861dSkettenis 	ar->ar_dval = sc->sc_regdata[i].dval;
743b393861dSkettenis 	ar->ar_vreg = sc->sc_regdata[i].vreg;
744b393861dSkettenis 	ar->ar_vmask = sc->sc_regdata[i].vmask;
745b393861dSkettenis 	ar->ar_base = sc->sc_regdata[i].base;
746b393861dSkettenis 	ar->ar_delta = sc->sc_regdata[i].delta;
747ae0af167Suaa 	ar->ar_nsteps = sc->sc_regdata[i].nsteps;
748ae0af167Suaa 	ar->ar_base2 = sc->sc_regdata[i].base2;
749ae0af167Suaa 	ar->ar_delta2 = sc->sc_regdata[i].delta2;
750ae0af167Suaa 	ar->ar_nsteps2 = sc->sc_regdata[i].nsteps2;
751b393861dSkettenis 
752b393861dSkettenis 	ar->ar_rd.rd_node = node;
753b393861dSkettenis 	ar->ar_rd.rd_cookie = ar;
754b393861dSkettenis 	ar->ar_rd.rd_get_voltage = axppmic_get_voltage;
755b393861dSkettenis 	ar->ar_rd.rd_set_voltage = axppmic_set_voltage;
756b393861dSkettenis 	ar->ar_rd.rd_enable = axppmic_enable;
757b393861dSkettenis 	regulator_register(&ar->ar_rd);
758b393861dSkettenis }
759b393861dSkettenis 
760b393861dSkettenis uint32_t
761b393861dSkettenis axppmic_get_voltage(void *cookie)
762b393861dSkettenis {
763b393861dSkettenis 	struct axppmic_regulator *ar = cookie;
764b393861dSkettenis 	uint32_t voltage;
765b393861dSkettenis 	uint8_t value;
766b393861dSkettenis 
767b393861dSkettenis 	value = axppmic_read_reg(ar->ar_sc, ar->ar_vreg);
768b393861dSkettenis 	value &= ar->ar_vmask;
769ae0af167Suaa 	if (ar->ar_base2 > 0 && value >= ar->ar_nsteps) {
770ae0af167Suaa 		voltage =
771ae0af167Suaa 		     ar->ar_base2 + (value - ar->ar_nsteps) * ar->ar_delta2;
772ae0af167Suaa 	} else {
773b393861dSkettenis 		voltage = ar->ar_base + value * ar->ar_delta;
774b393861dSkettenis 	}
775b393861dSkettenis 	return voltage;
776b393861dSkettenis }
777b393861dSkettenis 
778b393861dSkettenis int
779b393861dSkettenis axppmic_set_voltage(void *cookie, uint32_t voltage)
780b393861dSkettenis {
781b393861dSkettenis 	struct axppmic_regulator *ar = cookie;
782b393861dSkettenis 	uint32_t value, reg;
783b393861dSkettenis 
784b393861dSkettenis 	if (voltage < ar->ar_base)
785b393861dSkettenis 		return EINVAL;
786ae0af167Suaa 	if (ar->ar_base2 > 0 && voltage >= ar->ar_base2) {
787ae0af167Suaa 		value = (voltage - ar->ar_base2) / ar->ar_delta2;
788ae0af167Suaa 		if (value >= ar->ar_nsteps2)
789ae0af167Suaa 			return EINVAL;
790ae0af167Suaa 		value += ar->ar_nsteps;
791ae0af167Suaa 	} else {
792b393861dSkettenis 		value = (voltage - ar->ar_base) / ar->ar_delta;
793ae0af167Suaa 		if (value >= ar->ar_nsteps)
794ae0af167Suaa 			return EINVAL;
795b393861dSkettenis 	}
796b393861dSkettenis 	if (value > ar->ar_vmask)
797b393861dSkettenis 		return EINVAL;
798b393861dSkettenis 
799b393861dSkettenis 	reg = axppmic_read_reg(ar->ar_sc, ar->ar_vreg);
800ae0af167Suaa 	axppmic_write_reg(ar->ar_sc, ar->ar_vreg,
801ae0af167Suaa 	    (reg & ~ar->ar_vmask) | (value & ar->ar_vmask));
802b393861dSkettenis 	return 0;
803b393861dSkettenis }
804b393861dSkettenis 
805b393861dSkettenis int
806b393861dSkettenis axppmic_enable(void *cookie, int on)
807b393861dSkettenis {
808b393861dSkettenis 	struct axppmic_regulator *ar = cookie;
809b393861dSkettenis 	uint8_t reg;
810b393861dSkettenis 
811b393861dSkettenis 	reg = axppmic_read_reg(ar->ar_sc, ar->ar_ereg);
812b393861dSkettenis 	reg &= ~ar->ar_emask;
813b393861dSkettenis 	if (on)
814b393861dSkettenis 		reg |= ar->ar_eval;
815b393861dSkettenis 	else
816b393861dSkettenis 		reg |= ar->ar_dval;
817b393861dSkettenis 	axppmic_write_reg(ar->ar_sc, ar->ar_ereg, reg);
818b393861dSkettenis 	return 0;
819b393861dSkettenis }
820de7daf7eSkettenis 
821de7daf7eSkettenis /* Sensors */
822de7daf7eSkettenis 
823de7daf7eSkettenis void	axppmic_update_sensors(void *);
824de7daf7eSkettenis void	axppmic_update_indicator(struct axppmic_softc *, int);
825e6b4a485Skettenis void	axppmic_update_percent(struct axppmic_softc *, int);
826e6b4a485Skettenis void	axppmic_update_amphour(struct axppmic_softc *, int);
827de7daf7eSkettenis void	axppmic_update_sensor(struct axppmic_softc *, int);
828de7daf7eSkettenis 
829de7daf7eSkettenis void
830de7daf7eSkettenis axppmic_attach_sensors(struct axppmic_softc *sc)
831de7daf7eSkettenis {
832de7daf7eSkettenis 	int i;
833de7daf7eSkettenis 
834de7daf7eSkettenis 	for (i = 0; sc->sc_sensdata[i].name; i++) {
835de7daf7eSkettenis 		KASSERT(i < AXPPMIC_NSENSORS);
836de7daf7eSkettenis 
837de7daf7eSkettenis 		sc->sc_sensor[i].type = sc->sc_sensdata[i].type;
838de7daf7eSkettenis 		strlcpy(sc->sc_sensor[i].desc, sc->sc_sensdata[i].name,
839de7daf7eSkettenis 		    sizeof(sc->sc_sensor[i].desc));
840de7daf7eSkettenis 		sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]);
841de7daf7eSkettenis 	}
842de7daf7eSkettenis 
843de7daf7eSkettenis 	axppmic_update_sensors(sc);
844de7daf7eSkettenis 	if (sensor_task_register(sc, axppmic_update_sensors, 5) == NULL) {
845de7daf7eSkettenis 		printf(", unable to register update task\n");
846de7daf7eSkettenis 		return;
847de7daf7eSkettenis 	}
848de7daf7eSkettenis 
849de7daf7eSkettenis 	strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
850de7daf7eSkettenis 	    sizeof(sc->sc_sensordev.xname));
851de7daf7eSkettenis 	sensordev_install(&sc->sc_sensordev);
852de7daf7eSkettenis }
853de7daf7eSkettenis 
854de7daf7eSkettenis void
855de7daf7eSkettenis axppmic_update_sensors(void *arg)
856de7daf7eSkettenis {
857de7daf7eSkettenis 	struct axppmic_softc *sc = arg;
858de7daf7eSkettenis 	int i;
859de7daf7eSkettenis 
860de7daf7eSkettenis 	for (i = 0; sc->sc_sensdata[i].name; i++) {
861e6b4a485Skettenis 		switch (sc->sc_sensdata[i].type) {
862e6b4a485Skettenis 		case SENSOR_INDICATOR:
863de7daf7eSkettenis 			axppmic_update_indicator(sc, i);
864e6b4a485Skettenis 			break;
865e6b4a485Skettenis 		case SENSOR_PERCENT:
866e6b4a485Skettenis 			axppmic_update_percent(sc, i);
867e6b4a485Skettenis 			break;
868e6b4a485Skettenis 		case SENSOR_AMPHOUR:
869a7aa1e79Skettenis 			axppmic_update_amphour(sc, i);
870e6b4a485Skettenis 			break;
871e6b4a485Skettenis 		default:
872de7daf7eSkettenis 			axppmic_update_sensor(sc, i);
873e6b4a485Skettenis 			break;
874e6b4a485Skettenis 		}
875de7daf7eSkettenis 	}
876de7daf7eSkettenis }
877de7daf7eSkettenis 
878de7daf7eSkettenis void
879de7daf7eSkettenis axppmic_update_indicator(struct axppmic_softc *sc, int i)
880de7daf7eSkettenis {
881de7daf7eSkettenis 	uint8_t reg = sc->sc_sensdata[i].reg;
882de7daf7eSkettenis 	uint8_t mask = sc->sc_sensdata[i].base;
883de7daf7eSkettenis 	uint8_t mask_ok = sc->sc_sensdata[i].delta;
884de7daf7eSkettenis 	uint8_t value;
885de7daf7eSkettenis 
886de7daf7eSkettenis 	value = axppmic_read_reg(sc, reg);
887de7daf7eSkettenis 	sc->sc_sensor[i].value = (value & mask) ? 1 : 0;
888de7daf7eSkettenis 	if (value & mask) {
889de7daf7eSkettenis 		sc->sc_sensor[i].status =
890de7daf7eSkettenis 		    (value & mask_ok) ? SENSOR_S_OK : SENSOR_S_WARN;
891de7daf7eSkettenis 	} else {
892de7daf7eSkettenis 		sc->sc_sensor[i].status = SENSOR_S_UNSPEC;
893de7daf7eSkettenis 	}
894de7daf7eSkettenis }
895de7daf7eSkettenis 
896de7daf7eSkettenis void
897e6b4a485Skettenis axppmic_update_percent(struct axppmic_softc *sc, int i)
898e6b4a485Skettenis {
899e6b4a485Skettenis 	uint8_t reg = sc->sc_sensdata[i].reg;
900e6b4a485Skettenis 	uint8_t mask = sc->sc_sensdata[i].base;
901e6b4a485Skettenis 	uint8_t mask_ok = sc->sc_sensdata[i].delta;
902e6b4a485Skettenis 	uint8_t value;
903e6b4a485Skettenis 
904e6b4a485Skettenis 	value = axppmic_read_reg(sc, reg);
905e6b4a485Skettenis 	sc->sc_sensor[i].value = (value & mask) * 1000;
906e6b4a485Skettenis 
907e6b4a485Skettenis 	if (value & mask_ok) {
908e6b4a485Skettenis 		if ((value & mask) <= sc->sc_crit)
909e6b4a485Skettenis 			sc->sc_sensor[i].status = SENSOR_S_CRIT;
910e6b4a485Skettenis 		else if ((value & mask) <= sc->sc_warn)
911e6b4a485Skettenis 			sc->sc_sensor[i].status = SENSOR_S_WARN;
912e6b4a485Skettenis 		else
913e6b4a485Skettenis 			sc->sc_sensor[i].status = SENSOR_S_OK;
914e6b4a485Skettenis 	} else {
915e6b4a485Skettenis 		sc->sc_sensor[i].status = SENSOR_S_UNSPEC;
916e6b4a485Skettenis 	}
917e6b4a485Skettenis }
918e6b4a485Skettenis 
919e6b4a485Skettenis void
920e6b4a485Skettenis axppmic_update_amphour(struct axppmic_softc *sc, int i)
921e6b4a485Skettenis {
922e6b4a485Skettenis 	uint8_t reg = sc->sc_sensdata[i].reg;
923e6b4a485Skettenis 	uint64_t base = sc->sc_sensdata[i].base;
924e6b4a485Skettenis 	uint64_t delta = sc->sc_sensdata[i].delta;
925e6b4a485Skettenis 	uint16_t value;
926e6b4a485Skettenis 
927e6b4a485Skettenis 	value = axppmic_read_reg(sc, reg);
928e6b4a485Skettenis 	sc->sc_sensor[i].status = (value & 0x80) ? SENSOR_S_OK : SENSOR_S_WARN;
929e6b4a485Skettenis 	value = ((value & 0x7f) << 8) | axppmic_read_reg(sc, reg + 1);
930e6b4a485Skettenis 	sc->sc_sensor[i].value = base + value * delta;
931e6b4a485Skettenis }
932e6b4a485Skettenis 
933e6b4a485Skettenis void
934de7daf7eSkettenis axppmic_update_sensor(struct axppmic_softc *sc, int i)
935de7daf7eSkettenis {
936de7daf7eSkettenis 	uint8_t reg = sc->sc_sensdata[i].reg;
937de7daf7eSkettenis 	uint64_t base = sc->sc_sensdata[i].base;
938de7daf7eSkettenis 	uint64_t delta = sc->sc_sensdata[i].delta;
939de7daf7eSkettenis 	uint16_t value;
940de7daf7eSkettenis 
941de7daf7eSkettenis 	value = axppmic_read_reg(sc, reg);
942de7daf7eSkettenis 	value = (value << 4) | axppmic_read_reg(sc, reg + 1);
943de7daf7eSkettenis 	sc->sc_sensor[i].value = base + value * delta;
944de7daf7eSkettenis }
945de7daf7eSkettenis 
946de7daf7eSkettenis void
947de7daf7eSkettenis axp209_powerdown(void)
948de7daf7eSkettenis {
949de7daf7eSkettenis 	axppmic_write_reg(axppmic_sc, AXP209_SDR, AXP209_SDR_SHUTDOWN);
950de7daf7eSkettenis }
951